Code coverage for /20081101/modules/book/book.install

Line #Times calledCode
1
<?php
2
// $Id: book.install,v 1.23 2008/10/08 03:27:55 webchick Exp $
3
4
/**
5
 * Implementation of hook_install().
6
 */
71
function book_install() {
8
  // Create tables.
91
  drupal_install_schema('book');
10
  // Add the node type.
111
  _book_install_type_create();
121
}
13
14
/**
15
 * Implementation of hook_uninstall().
16
 */
171
function book_uninstall() {
18
  // Delete menu links.
190
  db_query("DELETE FROM {menu_links} WHERE module = 'book'");
200
  menu_cache_clear_all();
21
  // Remove tables.
220
  drupal_uninstall_schema('book');
230
}
24
251
function _book_install_type_create() {
26
  // Create an additional node type.
27
  $book_node_type = array(
281
    'type' => 'book',
291
    'name' => t('Book page'),
301
    'base' => 'node_content',
311
    '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.'),
321
    'custom' => 1,
331
    'modified' => 1,
341
    'locked' => 0,
351
  );
36
371
  $book_node_type = node_type_set_defaults($book_node_type);
381
  node_type_save($book_node_type);
39
  // Default to not promoted.
401
  variable_set('node_options_book', array('status'));
41
  // Use this default type for adding content to books.
421
  variable_set('book_allowed_types', array('book'));
431
  variable_set('book_child_type', 'book');
441
}
45
46
/**
47
 * Drupal 5.x to 6.x update.
48
 *
49
 * This function moves any existing book hierarchy into the new structure
used
50
 * in the 6.x module.  Rather than storing the hierarchy in the {book}
table,
51
 * the menu API is used to store the hierarchy in the {menu_links} table
and the
52
 * {book} table serves to uniquely connect a node to a menu link.
53
 *
54
 * In order to accomplish this, the current hierarchy is processed using a
stack.
55
 * The stack insures that each parent is processed before any of its
children
56
 * in the book hierarchy, and is compatible with batched update processing.
57
 *
58
 */
591
function book_update_6000() {
600
  $ret = array();
61
62
  // Set up for a multi-part update.
630
  if (!isset($_SESSION['book_update_6000'])) {
64
650
    $schema['book'] = array(
66
      'fields' => array(
670
        'mlid'    => array('type' => 'int', 'unsigned' => TRUE, 'not null'
=> TRUE, 'default' => 0),
680
        'nid'     => array('type' => 'int', 'unsigned' => TRUE, 'not null'
=> TRUE, 'default' => 0),
690
        'bid' => array('type' => 'int', 'unsigned' => TRUE, 'not null' =>
TRUE, 'default' => 0),
700
      ),
710
      'primary key' => array('mlid'),
72
      'unique keys' => array(
730
        'nid' => array('nid'),
740
      ),
75
      'indexes' => array(
760
        'bid' => array('bid'),
770
      ),
78
    );
79
    // Add the node type.
800
    _book_install_type_create();
81
82
    // Fix role permissions to account for the changed names
83
    // Setup the array holding strings to match and the corresponding
84
    // strings to replace them with.
85
    $replace = array(
860
      'outline posts in books' => 'administer book outlines',
870
      'create book pages' => 'create book content',
880
      'edit book pages' => 'edit any book content',
890
      'edit own book pages' => 'edit own book content',
900
      'see printer-friendly version' => 'access printer-friendly version',
910
    );
92
93
    // Loop over all the roles, and do the necessary transformations.
940
    $query = db_query("SELECT rid, perm FROM {permission} ORDER BY rid");
950
    while ($role = db_fetch_object($query)) {
96
      // Replace all the old permissions with the corresponding new
permissions.
970
      $fixed_perm = strtr($role->perm, $replace);
98
      // If the user could previously create book pages, they should get
the new
99
      // 'add content to books' permission.
1000
      if (strpos($role->perm, 'create book pages') !== FALSE) {
1010
        $fixed_perm .= ', add content to books';
1020
      }
103
      // Only save if the permissions have changed.
1040
      if ($fixed_perm != $role->perm) {
1050
        $ret[] = update_sql("UPDATE {permission} SET perm = '$fixed_perm'
WHERE rid = $role->rid");
1060
      }
1070
    }
108
109
    // Determine whether there are any existing nodes in the book
hierarchy.
1100
    if (db_result(db_query("SELECT COUNT(*) FROM {book}"))) {
111
      // Temporary table for the old book hierarchy; we'll discard revision
info.
1120
      $schema['book_temp'] = array(
113
        'fields' => array(
1140
          'nid'    => array('type' => 'int', 'unsigned' => TRUE, 'not null'
=> TRUE, 'default' => 0),
1150
          'parent' => array('type' => 'int', 'not null' => TRUE, 'default'
=> 0),
1160
          'weight' => array('type' => 'int', 'not null' => TRUE, 'default'
=> 0, 'size' => 'tiny')
1170
        ),
118
        'indexes' => array(
1190
          'parent' => array('parent')
1200
        ),
1210
        'primary key' => array('nid'),
122
      );
123
1240
      db_create_table($ret, 'book_temp', $schema['book_temp']);
125
126
      // Insert each node in the old table into the temporary table.
1270
      $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");
1280
      $ret[] = update_sql("DROP TABLE {book}");
129
1300
      db_create_table($ret, 'book', $schema['book']);
131
1320
      $_SESSION['book_update_6000_orphans']['from'] = 0;
1330
      $_SESSION['book_update_6000'] = array();
1340
      $result = db_query("SELECT * from {book_temp} WHERE parent = 0");
135
136
      // Collect all books - top-level nodes.
1370
      while ($a = db_fetch_array($result)) {
1380
        $_SESSION['book_update_6000'][] = $a;
1390
      }
1400
      $ret['#finished'] = FALSE;
1410
      return $ret;
1420
    }
143
    else {
144
      // No exising nodes in the hierarchy, so drop the table and re-create
it.
1450
      $ret[] = update_sql("DROP TABLE {book}");
1460
      db_create_table($ret, 'book', $schema['book']);
1470
      return $ret;
148
    }
1490
  }
1500
  elseif ($_SESSION['book_update_6000_orphans']) {
151
    // Do the first batched part of the update - collect orphans.
1520
    $update_count = 400; // Update this many at a time.
153
1540
    $result = db_query_range("SELECT * FROM {book_temp}",
$_SESSION['book_update_6000_orphans']['from'], $update_count);
1550
    $has_rows = FALSE;
156
    // Go through the next $update_count book pages and locate the orphans.
1570
    while ($book = db_fetch_array($result)) {
1580
      $has_rows = TRUE;
159
      // Orphans are defined as nodes whose parent does not exist in the
table.
1600
      if ($book['parent'] && !db_result(db_query("SELECT COUNT(*) FROM
{book_temp} WHERE nid = %d", $book['parent']))) {
1610
        if (empty($_SESSION['book_update_6000_orphans']['book'])) {
162
          // The first orphan becomes the parent for all other orphans.
1630
          $book['parent'] = 0;
1640
          $_SESSION['book_update_6000_orphans']['book'] = $book;
1650
          $ret[] = array('success' => TRUE, 'query' => 'Relocated orphan
book pages.');
1660
        }
167
        else {
168
          // Re-assign the parent value of the book, and add it to the
stack.
1690
          $book['parent'] =
$_SESSION['book_update_6000_orphans']['book']['nid'];
1700
          $_SESSION['book_update_6000'][] = $book;
171
        }
1720
      }
1730
    }
1740
    if ($has_rows) {
1750
      $_SESSION['book_update_6000_orphans']['from'] += $update_count;
1760
    }
177
    else {
1780
      if (!empty($_SESSION['book_update_6000_orphans']['book'])) {
179
        // The orphans' parent is added last, so it will be processed
first.
1800
        $_SESSION['book_update_6000'][] =
$_SESSION['book_update_6000_orphans']['book'];
1810
      }
1820
      $_SESSION['book_update_6000_orphans'] = FALSE;
183
    }
1840
    $ret['#finished'] = FALSE;
185
1860
    return $ret;
1870
  }
188
  else {
189
    // Run the next batched part of the update.
1900
    $update_count = 100; // Update this many at a time
191
1920
    while ($update_count && $_SESSION['book_update_6000']) {
193
      // Get the last node off the stack.
1940
      $book = array_pop($_SESSION['book_update_6000']);
195
196
      // Add all of this node's children to the stack.
1970
      $result = db_query("SELECT * FROM {book_temp} WHERE parent = %d",
$book['nid']);
1980
      while ($a = db_fetch_array($result)) {
1990
        $_SESSION['book_update_6000'][] = $a;
2000
      }
201
2020
      if ($book['parent']) {
203
        // If its not a top level page, get its parent's mlid.
2040
        $parent = db_fetch_array(db_query("SELECT b.mlid AS plid, b.bid
FROM {book} b WHERE b.nid = %d", $book['parent']));
2050
        $book = array_merge($book, $parent);
2060
      }
207
      else {
208
        // There is no parent - this is a new book.
2090
        $book['plid'] = 0;
2100
        $book['bid'] = $book['nid'];
211
      }
212
213
      $book += array(
2140
        'module' => 'book',
2150
        'link_path' => 'node/' . $book['nid'],
2160
        'router_path' => 'node/%',
2170
        'menu_name' => 'book-toc-' . $book['bid'],
2180
      );
2190
      $book = array_merge($book, db_fetch_array(db_query("SELECT title AS
link_title FROM {node} WHERE nid = %d", $book['nid'])));
220
221
      // Items with depth > MENU_MAX_DEPTH cannot be saved.
2220
      if (menu_link_save($book)) {
2230
        db_query("INSERT INTO {book} (mlid, nid, bid) VALUES (%d, %d, %d)",
$book['mlid'], $book['nid'], $book['bid']);
2240
      }
225
      else {
226
        // The depth was greater then MENU_MAX_DEPTH, so attach it to the
227
        // closest valid parent.
2280
        $book['plid'] = db_result(db_query("SELECT plid FROM {menu_links}
WHERE mlid = %d", $book['plid']));
2290
        if (menu_link_save($book)) {
2300
          db_query("INSERT INTO {book} (mlid, nid, bid) VALUES (%d, %d,
%d)", $book['mlid'], $book['nid'], $book['bid']);
2310
        }
232
      }
2330
      $update_count--;
2340
    }
2350
    $ret['#finished'] = FALSE;
236
  }
237
2380
  if (empty($_SESSION['book_update_6000'])) {
2390
    $ret['#finished'] = TRUE;
2400
    $ret[] = array('success' => TRUE, 'query' => 'Relocated existing book
pages.');
2410
    $ret[] = update_sql("DROP TABLE {book_temp}");
2420
    unset($_SESSION['book_update_6000']);
2430
    unset($_SESSION['book_update_6000_orphans']);
2440
  }
245
2460
  return $ret;
2470
}
248
249
/**
250
 * Implementation of hook_schema().
251
 */
2521
function book_schema() {
2531
  $schema['book'] = array(
2541
  'description' => t('Stores book outline information. Uniquely connects
each node in the outline to a link in {menu_links}'),
255
    'fields' => array(
256
      'mlid' => array(
2571
        'type' => 'int',
2581
        'unsigned' => TRUE,
2591
        'not null' => TRUE,
2601
        'default' => 0,
2611
        'description' => t("The book page's {menu_links}.mlid."),
2621
      ),
263
      'nid' => array(
2641
        'type' => 'int',
2651
        'unsigned' => TRUE,
2661
        'not null' => TRUE,
2671
        'default' => 0,
2681
        'description' => t("The book page's {node}.nid."),
2691
      ),
270
      'bid' => array(
2711
        'type' => 'int',
2721
        'unsigned' => TRUE,
2731
        'not null' => TRUE,
2741
        'default' => 0,
2751
        'description' => t("The book ID is the {book}.nid of the top-level
page."),
2761
      ),
2771
    ),
2781
    'primary key' => array('mlid'),
279
    'unique keys' => array(
2801
      'nid' => array('nid'),
2811
    ),
282
    'indexes' => array(
2831
      'bid' => array('bid'),
2841
    ),
285
  );
286
2871
  return $schema;
2880
}
2891