| webmaster@1 | 1 <?php | 
| webmaster@1 | 2 // $Id: book.install,v 1.20 2008/01/10 18:13:42 goba Exp $ | 
| webmaster@1 | 3 | 
| webmaster@1 | 4 /** | 
| webmaster@1 | 5  * Implementation of hook_install(). | 
| webmaster@1 | 6  */ | 
| webmaster@1 | 7 function book_install() { | 
| webmaster@1 | 8   // Create tables. | 
| webmaster@1 | 9   drupal_install_schema('book'); | 
| webmaster@1 | 10   // Add the node type. | 
| webmaster@1 | 11   _book_install_type_create(); | 
| webmaster@1 | 12 } | 
| webmaster@1 | 13 | 
| webmaster@1 | 14 /** | 
| webmaster@1 | 15  * Implementation of hook_uninstall(). | 
| webmaster@1 | 16  */ | 
| webmaster@1 | 17 function book_uninstall() { | 
| webmaster@1 | 18   // Delete menu links. | 
| webmaster@1 | 19   db_query("DELETE FROM {menu_links} WHERE module = 'book'"); | 
| webmaster@1 | 20   menu_cache_clear_all(); | 
| webmaster@1 | 21   // Remove tables. | 
| webmaster@1 | 22   drupal_uninstall_schema('book'); | 
| webmaster@1 | 23 } | 
| webmaster@1 | 24 | 
| webmaster@1 | 25 function _book_install_type_create() { | 
| webmaster@1 | 26   // Create an additional node type | 
| webmaster@1 | 27   $book_node_type = array( | 
| webmaster@1 | 28     'type' => 'book', | 
| webmaster@1 | 29     'name' => t('Book page'), | 
| webmaster@1 | 30     'module' => 'node', | 
| webmaster@1 | 31     'description' => t('A <em>book page</em> is a page of content, organized into a collection of related entries collectively known as a <em>book</em>. A <em>book page</em> automatically displays links to adjacent pages, providing a simple navigation system for organizing and reviewing structured content.'), | 
| webmaster@1 | 32     'custom' => TRUE, | 
| webmaster@1 | 33     'modified' => TRUE, | 
| webmaster@1 | 34     'locked' => FALSE, | 
| webmaster@1 | 35   ); | 
| webmaster@1 | 36 | 
| webmaster@1 | 37   $book_node_type = (object)_node_type_set_defaults($book_node_type); | 
| webmaster@1 | 38   node_type_save($book_node_type); | 
| webmaster@1 | 39   // Default to not promoted. | 
| webmaster@1 | 40   variable_set('node_options_book', array('status')); | 
| webmaster@1 | 41   // Use this default type for adding content to books. | 
| webmaster@1 | 42   variable_set('book_allowed_types', array('book')); | 
| webmaster@1 | 43   variable_set('book_child_type', 'book'); | 
| webmaster@1 | 44 } | 
| webmaster@1 | 45 | 
| webmaster@1 | 46 /** | 
| webmaster@1 | 47  * Drupal 5.x to 6.x update. | 
| webmaster@1 | 48  * | 
| webmaster@1 | 49  * This function moves any existing book hierarchy into the new structure used | 
| webmaster@1 | 50  * in the 6.x module.  Rather than storing the hierarchy in the {book} table, | 
| webmaster@1 | 51  * the menu API is used to store the hierarchy in the {menu_links} table and the | 
| webmaster@1 | 52  * {book} table serves to uniquely connect a node to a menu link. | 
| webmaster@1 | 53  * | 
| webmaster@1 | 54  * In order to accomplish this, the current hierarchy is processed using a stack. | 
| webmaster@1 | 55  * The stack insures that each parent is processed before any of its children | 
| webmaster@1 | 56  * in the book hierarchy, and is compatible with batched update processing. | 
| webmaster@1 | 57  * | 
| webmaster@1 | 58  */ | 
| webmaster@1 | 59 function book_update_6000() { | 
| webmaster@1 | 60   $ret = array(); | 
| webmaster@1 | 61 | 
| webmaster@1 | 62   // Set up for a multi-part update. | 
| webmaster@1 | 63   if (!isset($_SESSION['book_update_6000'])) { | 
| webmaster@1 | 64 | 
| webmaster@1 | 65     $schema['book'] = array( | 
| webmaster@1 | 66       'fields' => array( | 
| webmaster@1 | 67         'mlid'    => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0), | 
| webmaster@1 | 68         'nid'     => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0), | 
| webmaster@1 | 69         'bid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0), | 
| webmaster@1 | 70       ), | 
| webmaster@1 | 71       'primary key' => array('mlid'), | 
| webmaster@1 | 72       'unique keys' => array( | 
| webmaster@1 | 73         'nid' => array('nid'), | 
| webmaster@1 | 74       ), | 
| webmaster@1 | 75       'indexes' => array( | 
| webmaster@1 | 76         'bid' => array('bid'), | 
| webmaster@1 | 77       ), | 
| webmaster@1 | 78     ); | 
| webmaster@1 | 79     // Add the node type. | 
| webmaster@1 | 80     _book_install_type_create(); | 
| webmaster@1 | 81 | 
| webmaster@1 | 82     // Fix role permissions to account for the changed names | 
| webmaster@1 | 83     // Setup the array holding strings to match and the corresponding | 
| webmaster@1 | 84     // strings to replace them with. | 
| webmaster@1 | 85     $replace = array( | 
| webmaster@1 | 86       'outline posts in books' => 'administer book outlines', | 
| webmaster@1 | 87       'create book pages' => 'create book content', | 
| webmaster@1 | 88       'edit book pages' => 'edit any book content', | 
| webmaster@1 | 89       'edit own book pages' => 'edit own book content', | 
| webmaster@1 | 90       'see printer-friendly version' => 'access printer-friendly version', | 
| webmaster@1 | 91     ); | 
| webmaster@1 | 92 | 
| webmaster@1 | 93     // Loop over all the roles, and do the necessary transformations. | 
| webmaster@1 | 94     $query = db_query("SELECT rid, perm FROM {permission} ORDER BY rid"); | 
| webmaster@1 | 95     while ($role = db_fetch_object($query)) { | 
| webmaster@1 | 96       // Replace all the old permissions with the corresponding new permissions. | 
| webmaster@1 | 97       $fixed_perm = strtr($role->perm, $replace); | 
| webmaster@1 | 98       // If the user could previously create book pages, they should get the new | 
| webmaster@1 | 99       // 'add content to books' permission. | 
| webmaster@1 | 100       if (strpos($role->perm, 'create book pages') !== FALSE) { | 
| webmaster@1 | 101         $fixed_perm .= ', add content to books'; | 
| webmaster@1 | 102       } | 
| webmaster@1 | 103       // Only save if the permissions have changed. | 
| webmaster@1 | 104       if ($fixed_perm != $role->perm) { | 
| webmaster@1 | 105         $ret[] = update_sql("UPDATE {permission} SET perm = '$fixed_perm' WHERE rid = $role->rid"); | 
| webmaster@1 | 106       } | 
| webmaster@1 | 107     } | 
| webmaster@1 | 108 | 
| webmaster@1 | 109     // Determine whether there are any existing nodes in the book hierarchy. | 
| webmaster@1 | 110     if (db_result(db_query("SELECT COUNT(*) FROM {book}"))) { | 
| webmaster@1 | 111       // Temporary table for the old book hierarchy; we'll discard revision info. | 
| webmaster@1 | 112       $schema['book_temp'] = array( | 
| webmaster@1 | 113         'fields' => array( | 
| webmaster@1 | 114           'nid'    => array('type' => 'int', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0), | 
| webmaster@1 | 115           'parent' => array('type' => 'int', 'not null' => TRUE, 'default' => 0), | 
| webmaster@1 | 116           'weight' => array('type' => 'int', 'not null' => TRUE, 'default' => 0, 'size' => 'tiny') | 
| webmaster@1 | 117         ), | 
| webmaster@1 | 118         'indexes' => array( | 
| webmaster@1 | 119           'parent' => array('parent') | 
| webmaster@1 | 120         ), | 
| webmaster@1 | 121         'primary key' => array('nid'), | 
| webmaster@1 | 122       ); | 
| webmaster@1 | 123 | 
| webmaster@1 | 124       db_create_table($ret, 'book_temp', $schema['book_temp']); | 
| webmaster@1 | 125 | 
| webmaster@1 | 126       // Insert each node in the old table into the temporary table. | 
| webmaster@1 | 127       $ret[] = update_sql("INSERT INTO {book_temp} (nid, parent, weight) SELECT b.nid, b.parent, b.weight FROM {book} b INNER JOIN {node} n on b.vid = n.vid"); | 
| webmaster@1 | 128       $ret[] = update_sql("DROP TABLE {book}"); | 
| webmaster@1 | 129 | 
| webmaster@1 | 130       db_create_table($ret, 'book', $schema['book']); | 
| webmaster@1 | 131 | 
| webmaster@1 | 132       $_SESSION['book_update_6000_orphans']['from'] = 0; | 
| webmaster@1 | 133       $_SESSION['book_update_6000'] = array(); | 
| webmaster@1 | 134       $result = db_query("SELECT * from {book_temp} WHERE parent = 0"); | 
| webmaster@1 | 135 | 
| webmaster@1 | 136       // Collect all books - top-level nodes. | 
| webmaster@1 | 137       while ($a = db_fetch_array($result)) { | 
| webmaster@1 | 138         $_SESSION['book_update_6000'][] = $a; | 
| webmaster@1 | 139       } | 
| webmaster@1 | 140       $ret['#finished'] = FALSE; | 
| webmaster@1 | 141       return $ret; | 
| webmaster@1 | 142     } | 
| webmaster@1 | 143     else { | 
| webmaster@1 | 144       // No exising nodes in the hierarchy, so drop the table and re-create it. | 
| webmaster@1 | 145       $ret[] = update_sql("DROP TABLE {book}"); | 
| webmaster@1 | 146       db_create_table($ret, 'book', $schema['book']); | 
| webmaster@1 | 147       return $ret; | 
| webmaster@1 | 148     } | 
| webmaster@1 | 149   } | 
| webmaster@1 | 150   elseif ($_SESSION['book_update_6000_orphans']) { | 
| webmaster@1 | 151     // Do the first batched part of the update - collect orphans. | 
| webmaster@1 | 152     $update_count = 400; // Update this many at a time | 
| webmaster@1 | 153 | 
| webmaster@1 | 154     $result = db_query_range("SELECT * FROM {book_temp}", $_SESSION['book_update_6000_orphans']['from'], $update_count); | 
| webmaster@1 | 155     $has_rows = FALSE; | 
| webmaster@1 | 156     // Go through the next $update_count book pages and locate the orphans. | 
| webmaster@1 | 157     while ($book = db_fetch_array($result)) { | 
| webmaster@1 | 158       $has_rows = TRUE; | 
| webmaster@1 | 159       // Orphans are defined as nodes whose parent does not exist in the table. | 
| webmaster@1 | 160       if ($book['parent'] && !db_result(db_query("SELECT COUNT(*) FROM {book_temp} WHERE nid = %d", $book['parent']))) { | 
| webmaster@1 | 161         if (empty($_SESSION['book_update_6000_orphans']['book'])) { | 
| webmaster@1 | 162           // The first orphan becomes the parent for all other orphans. | 
| webmaster@1 | 163           $book['parent'] = 0; | 
| webmaster@1 | 164           $_SESSION['book_update_6000_orphans']['book'] = $book; | 
| webmaster@1 | 165           $ret[] = array('success' => TRUE, 'query' => 'Relocated orphan book pages.'); | 
| webmaster@1 | 166         } | 
| webmaster@1 | 167         else { | 
| webmaster@1 | 168           // Re-assign the parent value of the book, and add it to the stack. | 
| webmaster@1 | 169           $book['parent'] = $_SESSION['book_update_6000_orphans']['book']['nid']; | 
| webmaster@1 | 170           $_SESSION['book_update_6000'][] = $book; | 
| webmaster@1 | 171         } | 
| webmaster@1 | 172       } | 
| webmaster@1 | 173     } | 
| webmaster@1 | 174     if ($has_rows) { | 
| webmaster@1 | 175       $_SESSION['book_update_6000_orphans']['from'] += $update_count; | 
| webmaster@1 | 176     } | 
| webmaster@1 | 177     else { | 
| webmaster@1 | 178       // Done with this part | 
| webmaster@1 | 179       if (!empty($_SESSION['book_update_6000_orphans']['book'])) { | 
| webmaster@1 | 180         // The orphans' parent is added last, so it will be processed first. | 
| webmaster@1 | 181         $_SESSION['book_update_6000'][] = $_SESSION['book_update_6000_orphans']['book']; | 
| webmaster@1 | 182       } | 
| webmaster@1 | 183       $_SESSION['book_update_6000_orphans'] = FALSE; | 
| webmaster@1 | 184     } | 
| webmaster@1 | 185     $ret['#finished'] = FALSE; | 
| webmaster@1 | 186     return $ret; | 
| webmaster@1 | 187   } | 
| webmaster@1 | 188   else { | 
| webmaster@1 | 189     // Do the next batched part of the update | 
| webmaster@1 | 190     $update_count = 100; // Update this many at a time | 
| webmaster@1 | 191 | 
| webmaster@1 | 192     while ($update_count && $_SESSION['book_update_6000']) { | 
| webmaster@1 | 193       // Get the last node off the stack. | 
| webmaster@1 | 194       $book = array_pop($_SESSION['book_update_6000']); | 
| webmaster@1 | 195 | 
| webmaster@1 | 196       // Add all of this node's children to the stack | 
| webmaster@1 | 197       $result = db_query("SELECT * FROM {book_temp} WHERE parent = %d", $book['nid']); | 
| webmaster@1 | 198       while ($a = db_fetch_array($result)) { | 
| webmaster@1 | 199         $_SESSION['book_update_6000'][] = $a; | 
| webmaster@1 | 200       } | 
| webmaster@1 | 201 | 
| webmaster@1 | 202       if ($book['parent']) { | 
| webmaster@1 | 203         // If its not a top level page, get its parent's mlid. | 
| webmaster@1 | 204         $parent = db_fetch_array(db_query("SELECT b.mlid AS plid, b.bid FROM {book} b WHERE b.nid = %d", $book['parent'])); | 
| webmaster@1 | 205         $book = array_merge($book, $parent); | 
| webmaster@1 | 206       } | 
| webmaster@1 | 207       else { | 
| webmaster@1 | 208         // There is not a parent - this is a new book. | 
| webmaster@1 | 209         $book['plid'] = 0; | 
| webmaster@1 | 210         $book['bid'] = $book['nid']; | 
| webmaster@1 | 211       } | 
| webmaster@1 | 212 | 
| webmaster@1 | 213       $book += array( | 
| webmaster@1 | 214         'module' => 'book', | 
| webmaster@1 | 215         'link_path' => 'node/'. $book['nid'], | 
| webmaster@1 | 216         'router_path' => 'node/%', | 
| webmaster@1 | 217         'menu_name' => 'book-toc-'. $book['bid'], | 
| webmaster@1 | 218       ); | 
| webmaster@1 | 219       $book = array_merge($book, db_fetch_array(db_query("SELECT title AS link_title FROM {node} WHERE nid = %d", $book['nid']))); | 
| webmaster@1 | 220 | 
| webmaster@1 | 221       // Items with depth > MENU_MAX_DEPTH cannot be saved. | 
| webmaster@1 | 222       if (menu_link_save($book)) { | 
| webmaster@1 | 223         db_query("INSERT INTO {book} (mlid, nid, bid) VALUES (%d, %d, %d)", $book['mlid'], $book['nid'], $book['bid']); | 
| webmaster@1 | 224       } | 
| webmaster@1 | 225       else { | 
| webmaster@1 | 226         // The depth was greater then MENU_MAX_DEPTH, so attach it to the | 
| webmaster@1 | 227         // closest valid parent. | 
| webmaster@1 | 228         $book['plid'] = db_result(db_query("SELECT plid FROM {menu_links} WHERE mlid = %d", $book['plid'])); | 
| webmaster@1 | 229         if (menu_link_save($book)) { | 
| webmaster@1 | 230           db_query("INSERT INTO {book} (mlid, nid, bid) VALUES (%d, %d, %d)", $book['mlid'], $book['nid'], $book['bid']); | 
| webmaster@1 | 231         } | 
| webmaster@1 | 232       } | 
| webmaster@1 | 233       $update_count--; | 
| webmaster@1 | 234     } | 
| webmaster@1 | 235     $ret['#finished'] = FALSE; | 
| webmaster@1 | 236   } | 
| webmaster@1 | 237 | 
| webmaster@1 | 238   if (empty($_SESSION['book_update_6000'])) { | 
| webmaster@1 | 239     $ret['#finished'] = TRUE; | 
| webmaster@1 | 240     $ret[] = array('success' => TRUE, 'query' => 'Relocated existing book pages.'); | 
| webmaster@1 | 241     $ret[] = update_sql("DROP TABLE {book_temp}"); | 
| webmaster@1 | 242     unset($_SESSION['book_update_6000']); | 
| webmaster@1 | 243     unset($_SESSION['book_update_6000_orphans']); | 
| webmaster@1 | 244   } | 
| webmaster@1 | 245 | 
| webmaster@1 | 246   return $ret; | 
| webmaster@1 | 247 } | 
| webmaster@1 | 248 | 
| webmaster@1 | 249 /** | 
| webmaster@1 | 250  * Implementation of hook_schema(). | 
| webmaster@1 | 251  */ | 
| webmaster@1 | 252 function book_schema() { | 
| webmaster@1 | 253   $schema['book'] = array( | 
| webmaster@1 | 254   'description' => t('Stores book outline information. Uniquely connects each node in the outline to a link in {menu_links}'), | 
| webmaster@1 | 255     'fields' => array( | 
| webmaster@1 | 256       'mlid' => array( | 
| webmaster@1 | 257         'type' => 'int', | 
| webmaster@1 | 258         'unsigned' => TRUE, | 
| webmaster@1 | 259         'not null' => TRUE, | 
| webmaster@1 | 260         'default' => 0, | 
| webmaster@1 | 261         'description' => t("The book page's {menu_links}.mlid."), | 
| webmaster@1 | 262       ), | 
| webmaster@1 | 263       'nid' => array( | 
| webmaster@1 | 264         'type' => 'int', | 
| webmaster@1 | 265         'unsigned' => TRUE, | 
| webmaster@1 | 266         'not null' => TRUE, | 
| webmaster@1 | 267         'default' => 0, | 
| webmaster@1 | 268         'description' => t("The book page's {node}.nid."), | 
| webmaster@1 | 269       ), | 
| webmaster@1 | 270       'bid' => array( | 
| webmaster@1 | 271         'type' => 'int', | 
| webmaster@1 | 272         'unsigned' => TRUE, | 
| webmaster@1 | 273         'not null' => TRUE, | 
| webmaster@1 | 274         'default' => 0, | 
| webmaster@1 | 275         'description' => t("The book ID is the {book}.nid of the top-level page."), | 
| webmaster@1 | 276       ), | 
| webmaster@1 | 277     ), | 
| webmaster@1 | 278     'primary key' => array('mlid'), | 
| webmaster@1 | 279     'unique keys' => array( | 
| webmaster@1 | 280       'nid' => array('nid'), | 
| webmaster@1 | 281     ), | 
| webmaster@1 | 282     'indexes' => array( | 
| webmaster@1 | 283       'bid' => array('bid'), | 
| webmaster@1 | 284     ), | 
| webmaster@1 | 285   ); | 
| webmaster@1 | 286 | 
| webmaster@1 | 287   return $schema; | 
| webmaster@1 | 288 } | 
| webmaster@1 | 289 | 
| webmaster@1 | 290 |