| 
webmaster@1
 | 
     1 <?php | 
| 
franck@19
 | 
     2 // $Id: book.install,v 1.20.2.1 2009/01/06 15:46:36 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( | 
| 
franck@19
 | 
   254   'description' => '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, | 
| 
franck@19
 | 
   261         'description' => "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, | 
| 
franck@19
 | 
   268         'description' => "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, | 
| 
franck@19
 | 
   275         'description' => "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  |