Parent Directory
|
Revision Log
|
Revision Graph
Fixing issue 165524 regarding regular settings
| 1 | <?php |
| 2 | // $Id: relativity.module,v 1.48 2007/10/24 17:45:32 darius Exp $ |
| 3 | |
| 4 | /** |
| 5 | * @file |
| 6 | * This module allows you to attach nodes to other nodes. |
| 7 | * |
| 8 | * To store this extra information, we need an auxiliary database table. |
| 9 | */ |
| 10 | |
| 11 | if (module_exists('views')) { |
| 12 | include_once('relativity_views.inc'); |
| 13 | } |
| 14 | |
| 15 | /** |
| 16 | * Generates an array of named nodes keyed by node type. |
| 17 | * With no args, returns relativity node types |
| 18 | */ |
| 19 | function relativity_node_list($use_blank='', $show_all=0) { |
| 20 | $node_list = array(); |
| 21 | |
| 22 | if ($show_all) { |
| 23 | $node_list = node_get_types('names'); |
| 24 | } |
| 25 | else { |
| 26 | $show_nodes = variable_get('relativity_allow_types', array()); |
| 27 | foreach($show_nodes as $key=>$type) { |
| 28 | if ($type != 'default') { |
| 29 | $node_list[$type] = node_get_types('name',$type); |
| 30 | } |
| 31 | } |
| 32 | } |
| 33 | |
| 34 | if ($use_blank) { |
| 35 | $node_list['default'] = t($use_blank); |
| 36 | } |
| 37 | |
| 38 | return $node_list; |
| 39 | } |
| 40 | |
| 41 | /** |
| 42 | * Lists nodes that could be attached to a given parent type. |
| 43 | * |
| 44 | * TODO: |
| 45 | * Alter this code so that node_access("view",$child) logic is impelemented in the SQL statement. |
| 46 | * Use pager_query to process the results. Maybe even have a sortable table |
| 47 | * with various filters for restricting what is seen. Someday, maybe :) |
| 48 | * javanaut |
| 49 | */ |
| 50 | function relativity_list_possible_children($type='', $parent_nid='') { |
| 51 | if (!$type && !$parent_nid) { |
| 52 | $type = arg(2); |
| 53 | $parent_nid = is_numeric(arg(4)) ? arg(4) : $_GET['parent_node'] + 0; |
| 54 | } |
| 55 | |
| 56 | $links = array(); |
| 57 | $parent = node_load($parent_nid); |
| 58 | $relativity_query = variable_get('relativity_child_query_'.$parent->type.'_'.$type, NULL); |
| 59 | $common_children_reqd = variable_get('relativity_common_child_'.$parent->type.'_'.$type, array()); |
| 60 | if ($relativity_query && $query = node_load($relativity_query)) { |
| 61 | //drupal_set_message("executing query ".print_r($query,1)); |
| 62 | foreach(relativity_execute_query($query, NULL, $parent_nid) as $chnid => $child) { |
| 63 | if ($child->type == $type) { |
| 64 | $links[] = theme('relativity_link', $child->title, "addparent/$child->nid/parent/$parent_nid", $parent_nid, ' '.theme_relativity_trace($child->relativity_trace)); |
| 65 | } |
| 66 | } |
| 67 | } |
| 68 | elseif (count($common_children_reqd)) { |
| 69 | $otherparents = relativity_list_grand_relatives($parent, 'child', 'parent', $common_children_reqd, array($type)); |
| 70 | |
| 71 | foreach($otherparents as $childparent) { |
| 72 | if (node_access("view",$childparent)) { |
| 73 | $links[] = theme('relativity_link', $childparent->title, "addparent/$childparent->nid/parent/$parent_nid", $parent_nid, 'common child required'); |
| 74 | } |
| 75 | } |
| 76 | } |
| 77 | else { |
| 78 | // So, look up all valid nids attached to this parent_node already.. |
| 79 | $result = db_query('SELECT n.nid FROM {node} n LEFT OUTER JOIN {relativity} r ON n.nid=r.nid WHERE n.type = \'%s\' AND r.parent_nid=%d', $type, $parent_nid); |
| 80 | $excluded_nids = array($parent_nid); |
| 81 | // The number of nids returned by this array should be reasonably small. |
| 82 | // It's the number of nodes attached to a given node already. |
| 83 | while($existing_nid = db_fetch_object($result)) { |
| 84 | $excluded_nids[] = $existing_nid->nid; |
| 85 | } |
| 86 | |
| 87 | $use_taxonomy = variable_get('relativity_use_taxonomy', 0); |
| 88 | if ($use_taxonomy) { |
| 89 | $result = db_query('SELECT DISTINCT n.nid, t.tid, v.vid FROM {node} n INNER JOIN {term_node} t ON n.nid = t.nid INNER JOIN {term_data} v ON t.tid = v.tid WHERE n.type = \'%s\' AND n.status = 1 ORDER BY v.vid, t.tid', $type); |
| 90 | } else { |
| 91 | $result = db_query('SELECT n.nid FROM {node} n WHERE n.type = \'%s\' AND n.status = 1 ORDER BY n.title', $type); |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | while($child = db_fetch_object($result)) { |
| 96 | if (in_array($child->nid, $excluded_nids)) { continue; } |
| 97 | $child_node = node_load($child->nid); |
| 98 | if (node_access('view', $child_node)) { |
| 99 | if ($use_taxonomy) { |
| 100 | $parent_tree = array_reverse(taxonomy_get_parents_all($child->tid)); |
| 101 | // Building the array key |
| 102 | for ($i=0; $i<count($parent_tree); $i++) { |
| 103 | if($i==0) { |
| 104 | $key = $parent_tree[$i]->vid.';'.$parent_tree[$i]->tid.';'; |
| 105 | } else { |
| 106 | $term = taxonomy_get_term($parent_tree[$i]->tid); |
| 107 | $key .= $parent_tree[$i]->tid.';'; |
| 108 | } |
| 109 | } |
| 110 | $links[$key][] = array('title' => $child_node->title, 'child_node' => $child_node->nid, 'parent_node' => $parent_nid); |
| 111 | } else { |
| 112 | $links[] = theme('relativity_link', $child_node->title, "addparent/$child_node->nid/parent/$parent_nid", $parent_nid); |
| 113 | } |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | if (count($links)) { |
| 118 | if ($use_taxonomy) { |
| 119 | print(theme('page', drupal_get_form('relativity_taxonomy_form', $links) )); |
| 120 | } else { |
| 121 | print(theme('page', theme('relativity_bullets', $links))); |
| 122 | } |
| 123 | } else { |
| 124 | drupal_set_message(t('There are no available !s items to attach', array('!s' => node_get_types('name',$type)))); |
| 125 | drupal_goto("node/$parent_nid"); |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | /** |
| 130 | * Lists all grandparents or grandchildren of the given node. |
| 131 | * Additionally, allow the direction of search to change directions by having different |
| 132 | * values for $rel_type1 and $rel_type2. |
| 133 | * @param $node the node to start searching from |
| 134 | * @param $rel_type1 Which direction to look ('parent' or 'child') |
| 135 | * @param $rel_type2 Which direction to look beyond children/parents that were found (grand)('parent' or 'child') |
| 136 | * @param $conduit_types array of connecting node types to restrict the search to |
| 137 | * @param $types array of grandparent/grandchild node types to restrict the results to |
| 138 | * @return array of grandparent/grandchild nodes that were found |
| 139 | */ |
| 140 | function relativity_list_grand_relatives($node, $rel_type1='child', $rel_type2='child', $conduit_types = NULL, $types = NULL, $exclude_circular_paths=TRUE) { |
| 141 | //$nodes = array(); |
| 142 | |
| 143 | // List all children/parents. Restrict list to $conduit_types if specified |
| 144 | $conduit_types_sql = ""; |
| 145 | if (is_array($conduit_types) && count($conduit_types)) { |
| 146 | $conduit_types_sql = " AND n.type IN ('".implode("','",$conduit_types)."') "; |
| 147 | } |
| 148 | |
| 149 | if ($rel_type1 == 'parent') { |
| 150 | $result = db_query("SELECT DISTINCT n.nid as nid FROM {node} n INNER JOIN {relativity} r ON n.nid=r.parent_nid WHERE r.nid=%d $conduit_types_sql", $node->nid); |
| 151 | } |
| 152 | else { |
| 153 | $result = db_query("SELECT DISTINCT n.nid as nid FROM {node} n INNER JOIN {relativity} r ON n.nid=r.nid WHERE r.parent_nid=%d $conduit_types_sql", $node->nid); |
| 154 | } |
| 155 | |
| 156 | while($obj = db_fetch_object($result)) { |
| 157 | $relatives[$obj->nid] = $obj->nid; |
| 158 | } |
| 159 | |
| 160 | if (is_array($relatives) && count($relatives)) { |
| 161 | // list all children/parents of the $relatives found. Restrict list to $conduit_types if specified |
| 162 | |
| 163 | // identify parents and children for exclusion |
| 164 | if ($exclude_circular_paths) { |
| 165 | $all_relatives[$node->nid] = $node->nid; // exclude self |
| 166 | |
| 167 | // parents |
| 168 | $result = db_query("SELECT DISTINCT n.nid as nid FROM {node} n INNER JOIN {relativity} r ON n.nid=r.parent_nid WHERE r.nid = %d", $node->nid); |
| 169 | while($obj = db_fetch_object($result)) { |
| 170 | $all_relatives[$obj->nid] = $obj->nid; |
| 171 | } |
| 172 | |
| 173 | // children |
| 174 | $result = db_query("SELECT DISTINCT n.nid as nid FROM {node} n INNER JOIN {relativity} r ON n.nid=r.nid WHERE r.parent_nid = %d", $node->nid); |
| 175 | while($obj = db_fetch_object($result)) { |
| 176 | $all_relatives[$obj->nid] = $obj->nid; |
| 177 | } |
| 178 | } |
| 179 | $all_relatives = is_array($all_relatives) ? $all_relatives : array(); |
| 180 | |
| 181 | $types_sql = ""; |
| 182 | if (is_array($types) && count($types)) { |
| 183 | $types_sql = " AND n.type IN ('".implode("','",$types)."') "; |
| 184 | } |
| 185 | |
| 186 | if ($rel_type2 == 'parent') { |
| 187 | $result = db_query("SELECT DISTINCT n.nid as nid FROM {node} n INNER JOIN {relativity} r ON n.nid=r.parent_nid WHERE r.nid IN (".implode(",",$relatives).") $types_sql"); |
| 188 | } |
| 189 | else { |
| 190 | $result = db_query("SELECT DISTINCT n.nid as nid FROM {node} n INNER JOIN {relativity} r ON n.nid=r.nid WHERE r.parent_nid IN (".implode(",",$relatives).") $types_sql"); |
| 191 | } |
| 192 | |
| 193 | while($obj = db_fetch_object($result)) { |
| 194 | if (!($exclude_circular_paths && isset($all_relatives[$obj->nid]))) { |
| 195 | $grand_relatives[$obj->nid] = node_load($obj->nid); |
| 196 | } |
| 197 | } |
| 198 | } |
| 199 | |
| 200 | return is_array($grand_relatives) ? $grand_relatives : array(); |
| 201 | } |
| 202 | |
| 203 | /** |
| 204 | * Delete the parent/node relationship |
| 205 | */ |
| 206 | function relativity_unparent_node() { |
| 207 | $output = ""; |
| 208 | $parent_nid = arg(2); |
| 209 | $child_nid = arg(3); |
| 210 | if (is_numeric($parent_nid) && is_numeric($child_nid)) { |
| 211 | $parent = node_load($parent_nid); |
| 212 | $child = node_load($child_nid); |
| 213 | if (relativity_may_unchild($parent, $child)) { |
| 214 | $result = db_query('DELETE FROM {relativity} WHERE nid = %d AND parent_nid = %d', $child_nid, $parent_nid); |
| 215 | drupal_set_message(t('Node relationship removed.')); |
| 216 | } |
| 217 | else { |
| 218 | drupal_set_message(t('Node relationship cannot currently be removed.')); |
| 219 | } |
| 220 | } |
| 221 | else { |
| 222 | drupal_set_message(t('Either that node does not exist or you don\'t have proper privileges to update it')); |
| 223 | } |
| 224 | drupal_goto('node/'.$parent_nid); |
| 225 | } |
| 226 | |
| 227 | /** |
| 228 | * Attach a node to its parent |
| 229 | */ |
| 230 | function relativity_addparent($child_nid="", $parent_nid="") { |
| 231 | if (!$child_nid && !$parent_nid) { |
| 232 | $child_nid = arg(2); |
| 233 | $parent_nid = arg(4); |
| 234 | } |
| 235 | $output = ""; |
| 236 | |
| 237 | db_query('INSERT INTO {relativity} (nid, parent_nid) VALUES (%d, %d)', $child_nid, $parent_nid); |
| 238 | drupal_set_message(t('Node relationship created.')); |
| 239 | drupal_goto('node/'.$parent_nid); |
| 240 | } |
| 241 | |
| 242 | /** |
| 243 | * Attach multiple nodes to its parent |
| 244 | */ |
| 245 | function relativity_addparent_multiple() { |
| 246 | $edit = $_POST['edit']; |
| 247 | $parent_nid = $_POST['parent_nid']; |
| 248 | if ($edit['child_nids']) { |
| 249 | $child_nids = array_keys($edit['child_nids']); |
| 250 | for ($i=0; $i<count($child_nids); $i++) { |
| 251 | db_query('INSERT INTO {relativity} (nid, parent_nid) VALUES (%d, %d)', $child_nids[$i], $parent_nid); |
| 252 | } |
| 253 | drupal_set_message(t('Node relationship created.')); |
| 254 | drupal_goto('node/'.$parent_nid); |
| 255 | } else { |
| 256 | drupal_set_message(t('You did not select a node!')); |
| 257 | drupal_goto('node/'.$parent_nid); |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | function relativity_menu($may_cache) { |
| 262 | global $_menu;// = menu_get_menu(); |
| 263 | $items = array(); |
| 264 | |
| 265 | if ($may_cache && variable_get('relativity_enforce_parent_rules', FALSE)) { |
| 266 | // * not working how I wanted it to |
| 267 | // * This needs node_add in node.module to check menu before displaying links |
| 268 | |
| 269 | // iterate through all node types and take over their node/add handlers |
| 270 | foreach(relativity_node_list() as $type){ |
| 271 | if (relativity_requires_parent($type)) { |
| 272 | //drupal_set_message("setting access for type $type"); |
| 273 | $items[] = array('path' => 'node/add/'. $type, 'title' => t('content type requires parent'), |
| 274 | 'callback' => 'node_add', |
| 275 | 'callback arguments' => array($type), |
| 276 | 'access' => 0,//user_access('administer content'), |
| 277 | 'type' => MENU_CALLBACK, |
| 278 | 'priority' => 1, |
| 279 | 'weight' => 1 |
| 280 | ); |
| 281 | } |
| 282 | } |
| 283 | } |
| 284 | |
| 285 | if (!$may_cache) { |
| 286 | if (arg(0) == 'node' && arg(1) == 'add' && array_key_exists(arg(2),relativity_node_list()) && arg(3) == 'parent' && is_numeric(arg(4))) { |
| 287 | // this is my crafty way of creating new nodes as children of parents, and |
| 288 | // not displaying any links to create them otherwise. |
| 289 | $_GET['parent_node'] = arg(4); |
| 290 | $items[] = array('path' => 'node/add/'. arg(2).'/parent/'.arg(4), 'title' => t('create content'), |
| 291 | 'callback' => 'node_add', |
| 292 | 'callback arguments' => array(arg(2)), |
| 293 | 'access' => node_access('create', arg(2)), |
| 294 | 'type' => MENU_CALLBACK, |
| 295 | 'weight' => 1 |
| 296 | ); |
| 297 | } |
| 298 | elseif (arg(0) == 'relativity' && arg(1) == 'listnodes' && array_key_exists(arg(2),relativity_node_list()) && arg(3) == 'parent' && is_numeric(arg(4))) { |
| 299 | |
| 300 | $items[] = array('path' => 'relativity/listnodes/'. arg(2).'/parent/'.arg(4), 'title' => t('list of !type nodes to attach', array('!type'=>node_get_types('name',arg(2)))), |
| 301 | 'callback' => 'relativity_list_possible_children', |
| 302 | 'access' => node_access('update', node_load(arg(4))) && user_access("access content"), |
| 303 | 'type' => MENU_CALLBACK |
| 304 | ); |
| 305 | } |
| 306 | elseif (arg(0) == 'relativity' && arg(1) == 'addparent' && is_numeric(arg(2)) && arg(3) == "parent" && is_numeric(arg(4))) { |
| 307 | $items[] = array('path' => 'relativity/addparent/'. arg(2) .'/parent/'. arg(4), 'title' => t('attach node to parent'), |
| 308 | 'callback' => 'relativity_addparent', |
| 309 | 'access' => node_access("view", node_load(arg(2))), |
| 310 | 'type' => MENU_CALLBACK |
| 311 | ); |
| 312 | } |
| 313 | elseif (arg(0) == 'relativity' && arg(1) == 'addparent' && arg(2) == 'multiple') { |
| 314 | $items[] = array('path' => 'relativity/addparent/multiple', 'title' => t('attach node to parent'), |
| 315 | 'callback' => 'relativity_addparent_multiple', |
| 316 | 'access' => node_access('view'), |
| 317 | 'type' => MENU_CALLBACK |
| 318 | ); |
| 319 | } |
| 320 | elseif (arg(0) == 'relativity' && arg(1) == 'unparent' && is_numeric(arg(2)) && is_numeric(arg(3))) { |
| 321 | $items[] = array('path' => 'relativity/unparent/'.arg(2).'/'.arg(3), 'title' => t('unparent node'), |
| 322 | 'callback' => 'relativity_unparent_node', |
| 323 | 'access' => node_access("update", node_load(arg(2))), |
| 324 | 'type' => MENU_CALLBACK |
| 325 | ); |
| 326 | } |
| 327 | } |
| 328 | else { |
| 329 | $items[] = array( |
| 330 | 'path' => 'admin/settings/relativity', |
| 331 | 'title' => t('Node relativity'), |
| 332 | 'description' => t('Node relativity settings.'), |
| 333 | 'callback' => 'drupal_get_form', |
| 334 | 'callback arguments' => array('relativity_regular_settings'), |
| 335 | 'access' => user_access('administer site configuration'), |
| 336 | 'type' => MENU_NORMAL_ITEM, // optional |
| 337 | ); |
| 338 | |
| 339 | $items[] = array('path' => 'admin/settings/relativity/regular', |
| 340 | 'title' => t('Regular settings'), |
| 341 | 'type' => MENU_DEFAULT_LOCAL_TASK, |
| 342 | 'weight' => -10 |
| 343 | ); |
| 344 | |
| 345 | $items[] = array( |
| 346 | 'path' => 'admin/settings/relativity/display', |
| 347 | 'title' => t('Display settings'), |
| 348 | 'callback' => 'drupal_get_form', |
| 349 | 'callback arguments' => array('relativity_display_settings'), |
| 350 | 'access' => user_access('administer site configuration'), |
| 351 | 'type' => MENU_LOCAL_TASK, |
| 352 | ); |
| 353 | |
| 354 | $items[] = array( |
| 355 | 'path' => 'admin/settings/relativity/advanced', |
| 356 | 'title' => t('Advanced settings'), |
| 357 | 'callback' => 'drupal_get_form', |
| 358 | 'callback arguments' => array('relativity_advanced_settings'), |
| 359 | 'access' => user_access('administer site configuration'), |
| 360 | 'type' => MENU_LOCAL_TASK, |
| 361 | ); |
| 362 | } |
| 363 | return $items; |
| 364 | } |
| 365 | |
| 366 | function relativity_regular_settings() { |
| 367 | $all_types = relativity_node_list('', TRUE); |
| 368 | $relativity_types = relativity_node_list('', FALSE); |
| 369 | |
| 370 | $group['description'] = array( |
| 371 | '#type' => 'item', |
| 372 | '#title' => '', |
| 373 | '#value' => t('Below are the general settings for node relationships for each node type. The !advanced and !display pages use the settings on this page, so be sure to save these settings before proceeding to either of them.', array('!display'=>l('Display settings', 'admin/settings/relativity/display'), '!advanced'=>l('Advanced settings', 'admin/settings/relativity/advanced'))), |
| 374 | ); |
| 375 | |
| 376 | $group['global_options'] = array( |
| 377 | '#type' => 'fieldset', |
| 378 | '#title' => t('Global Options'), |
| 379 | ); |
| 380 | |
| 381 | $group['global_options']['relativity_allow_types'] = array( |
| 382 | '#type' => 'select', |
| 383 | '#title' => t('Node types that can be involved in relationships'), |
| 384 | '#default_value' => variable_get('relativity_allow_types', 'default'), |
| 385 | '#options' => relativity_node_list('',TRUE), |
| 386 | '#description' => t('What types of nodes should Node Relativity use? Be sure to include any node type involved (both parent and children types). You can use Ctrl+Click to unselect an option. After saving this, configuration options will appear for all of the node types that you specified. After selecting appropriate settings for each node type, please save again.'), |
| 387 | '#size' => count(relativity_node_list('',TRUE)), |
| 388 | '#multiple' => TRUE, |
| 389 | ); |
| 390 | |
| 391 | |
| 392 | // set to default values if type not selected |
| 393 | foreach ($all_types as $type=>$name) { |
| 394 | if (!in_array($type, array_keys($relativity_types))) { // type is not in relativity_types |
| 395 | variable_set('relativity_parent_ord_'.$type, 'any'); |
| 396 | variable_set('relativity_type_'.$type, array()); |
| 397 | } |
| 398 | } |
| 399 | |
| 400 | // no node types to manage |
| 401 | if (count($relativity_types) == 0) { |
| 402 | return system_settings_form($group); |
| 403 | } |
| 404 | |
| 405 | $group['global_options']['relativity_ancestors_label'] = array( |
| 406 | '#type' => 'textfield', |
| 407 | '#title' => t('Label for "Ancestor nodes"'), |
| 408 | '#default_value' => variable_get('relativity_ancestors_label', t('Ancestor nodes')), |
| 409 | '#size' => 60, |
| 410 | '#maxlength' => 250, |
| 411 | ); |
| 412 | |
| 413 | $group['global_options']['relativity_parents_label'] = array( |
| 414 | '#type' => 'textfield', |
| 415 | '#title' => t('Label for "Parent nodes"'), |
| 416 | '#default_value' => variable_get('relativity_parents_label', t('Parent nodes')), |
| 417 | '#size' => 60, |
| 418 | '#maxlength' => 250, |
| 419 | ); |
| 420 | |
| 421 | $group['global_options']['relativity_children_label'] = array( |
| 422 | '#type' => 'textfield', |
| 423 | '#title' => t('Label for "Children nodes"'), |
| 424 | '#default_value' => variable_get('relativity_children_label', t('Children nodes')), |
| 425 | '#size' => 60, |
| 426 | '#maxlength' => 250, |
| 427 | ); |
| 428 | |
| 429 | $group['global_options']['relativity_actions_label'] = array( |
| 430 | '#type' => 'textfield', |
| 431 | '#title' => t('Label for "Link operations"'), |
| 432 | '#default_value' => variable_get('relativity_actions_label', t('Link operations')), |
| 433 | '#size' => 60, |
| 434 | '#maxlength' => 250, |
| 435 | ); |
| 436 | |
| 437 | |
| 438 | $collapsed = (count($relativity_types) == 1) ? FALSE : TRUE; |
| 439 | foreach ($relativity_types as $type=>$name) { |
| 440 | $group['node_'.$type.'_options'] = array( |
| 441 | '#type' => 'fieldset', |
| 442 | '#collapsible' => TRUE, |
| 443 | '#collapsed' => $collapsed, |
| 444 | '#title' => t('Options for !name (!type) nodes', array('!name'=>$name, '!type' =>$type)), |
| 445 | ); |
| 446 | |
| 447 | $group['node_'.$type.'_options']['relativity_parent_ord_'.$type] = array( |
| 448 | '#type' => 'select', |
| 449 | '#title' => t('Parental Ordinality'), |
| 450 | '#default_value' => variable_get('relativity_parent_ord_'.$type, 'any'), |
| 451 | '#options' => array('any'=>t('any'), 'one'=>t('one'), 'none'=>t('none'), 'one or more'=>t('one or more')), |
| 452 | '#description' => t('How many parents can this node type have?'), |
| 453 | ); |
| 454 | |
| 455 | $group['node_'.$type.'_options']['relativity_type_'.$type] = array( |
| 456 | '#type' => 'select', |
| 457 | '#title' => t('Allowable Child Node types'), |
| 458 | '#default_value' => variable_get('relativity_type_'.$type, array()), |
| 459 | '#options' => relativity_node_list('',FALSE), |
| 460 | '#description' => t('What types of nodes are allowed to be attached to this type?'), |
| 461 | '#size' => count(relativity_node_list('',FALSE)), |
| 462 | '#multiple' => TRUE, |
| 463 | ); |
| 464 | } |
| 465 | |
| 466 | return system_settings_form($group); |
| 467 | } |
| 468 | |
| 469 | function relativity_advanced_settings() { |
| 470 | $allow_types = relativity_node_list(); |
| 471 | |
| 472 | $group['global_options'] = array( |
| 473 | '#type' => 'fieldset', |
| 474 | '#title' => t('Global Options'), |
| 475 | ); |
| 476 | |
| 477 | $group['global_options']['relativity_enforce_parent_rules'] = array( |
| 478 | '#type' => 'checkbox', |
| 479 | '#title' => t('Enforce Parental Rules'), |
| 480 | '#return_value' => 1, |
| 481 | '#default_value' => variable_get('relativity_enforce_parent_rules', 0), |
| 482 | '#description' => t('If checked, nodes cannot be created without a parent if they require a parent to exist.'), |
| 483 | ); |
| 484 | |
| 485 | // Node Sorting Options |
| 486 | $group['sorting_options'] = array( |
| 487 | '#type' => 'fieldset', |
| 488 | '#title' => t('Node Sorting Options'), |
| 489 | ); |
| 490 | |
| 491 | $group['global_options']['relativity_use_taxonomy'] = array( |
| 492 | '#type' => 'checkbox', |
| 493 | '#title' => t('Use Taxonomy to attach nodes'), |
| 494 | '#return_value' => 1, |
| 495 | '#default_value' => variable_get('relativity_use_taxonomy', 0), |
| 496 | '#description' => t('If checked, nodes cannot be attached if they don\'t belong to a taxonomy term. When listing nodes to attach, possible children will be displayed in a taxonomy tree.'), |
| 497 | ); |
| 498 | |
| 499 | // let admins specify sort order for node types |
| 500 | $ntypes = count($allow_types); |
| 501 | foreach($allow_types as $type => $name) { |
| 502 | $node_order[$type] = variable_get('relativity_node_order_'.$type, -1); |
| 503 | if (($node_order[$type] < 1) || ($node_order[$type] > $ntypes)) { |
| 504 | $node_order[$type] = 1; // default to 1 |
| 505 | } |
| 506 | } |
| 507 | |
| 508 | // we need a keyed array where numbers are sort order |
| 509 | $sort_options = range(1, $ntypes); |
| 510 | foreach($sort_options as $opt) { |
| 511 | $options[$opt] = $opt; |
| 512 | } |
| 513 | |
| 514 | // display list of node types sorted by ascending sort order |
| 515 | for($i=1; $i<=$ntypes; $i++) { |
| 516 | foreach($allow_types as $type => $name) { |
| 517 | if ($node_order[$type] == $i) { |
| 518 | $group['sorting_options']['relativity_node_order_'.$type] = array( |
| 519 | '#type' => 'select', |
| 520 | '#title' => t('Sort Order for !name Nodes', array('!name'=>$name)), |
| 521 | '#default_value' => variable_get('relativity_node_order_'.$type, ""), |
| 522 | '#options' => $options, |
| 523 | ); |
| 524 | } |
| 525 | } |
| 526 | } |
| 527 | |
| 528 | $collapsed = (count(relativity_node_list()) == 1) ? FALSE : TRUE; |
| 529 | foreach(relativity_node_list() as $type=>$name) { |
| 530 | $group['node_'.$type.'_options'] = array( |
| 531 | '#type' => 'fieldset', |
| 532 | '#collapsible' => TRUE, |
| 533 | '#collapsed' => $collapsed, |
| 534 | '#title' => t('!label Options for !name (!type) nodes', array('!name'=>$name, '!type' =>$type, '!label'=>$label[$tab])), |
| 535 | ); |
| 536 | |
| 537 | foreach (relativity_node_list() as $chtype=>$chname) { |
| 538 | if (in_array($chtype, variable_get('relativity_type_'.$type, array()))) { |
| 539 | $group['node_'.$type.'_options']['relativity_child_ord_'.$type.'_'.$chtype] = array( |
| 540 | '#type' => 'select', |
| 541 | '#title' => t('!chname Child Ordinality for !pname Parents', array('!chname'=>$chname, '!pname'=>$name)), |
| 542 | '#default_value' => variable_get('relativity_child_ord_'.$type.'_'.$chtype, 'any'), |
| 543 | '#options' => array('any'=>t('any'), '1'=>t('1'), '2'=>t('2'), '3'=>t('3'), '4'=>t('4'), '5'=>t('5'), '6'=>t('6'), '7'=>t('7'), '8'=>t('8'), '9'=>t('9'), '10'=>t('10')), |
| 544 | ); |
| 545 | |
| 546 | |
| 547 | // "Require Common Child of specified type" feature |
| 548 | // find the intersection of 'relativity_type_'.$type and 'relativity_type_'.$chtype (common allowable child types for parent and child) |
| 549 | $common_child_types = array_intersect(variable_get('relativity_type_'.$type, array()), variable_get('relativity_type_'.$chtype, array())); |
| 550 | if (count($common_child_types)) { |
| 551 | foreach($common_child_types as $cchtype) { |
| 552 | $common_types[$cchtype] = node_get_types('name',$cchtype); |
| 553 | } |
| 554 | $group['node_'.$type.'_options']['relativity_common_child_'.$type.'_'.$chtype] = array( |
| 555 | '#type' => 'select', |
| 556 | '#title' => t('Require Common Child Node Types for !chname Children', array('!chname'=>$chname)), |
| 557 | '#default_value' => variable_get('relativity_common_child_'.$type.'_'.$chtype, array()), |
| 558 | '#options' => $common_types, |
| 559 | '#description' => t('Require that any child of this type already have a child in common of the specified type. This allows particular circular relationships to be created.'), |
| 560 | '#extra' => 0, |
| 561 | '#multiple' => TRUE, |
| 562 | ); |
| 563 | } |
| 564 | |
| 565 | // list out possible relativity_queries that could be used to define this relationship type |
| 566 | $possible_queries = NULL; |
| 567 | // NOTE: This query depends on PHP's formatting of serialized arrays. If the implementation changes, this will need to be updated. Yes, it's a cheap hack ;) |
| 568 | $sql = "SELECT n.nid, n.title FROM {node} n INNER JOIN {relativity_query} r ON r.nid=n.nid WHERE n.type='relativity' AND r.search_types LIKE '%\"$chtype\"%'"; |
| 569 | $result = db_query($sql); |
| 570 | while($obj = db_fetch_object($result)) { |
| 571 | $possible_queries[$obj->nid] = $obj->title; |
| 572 | } |
| 573 | if (is_array($possible_queries) && count($possible_queries)) { |
| 574 | $possible_queries[0] = t('none'); |
| 575 | //drupal_set_message($sql." found possible queries: ".print_r($possible_queries,1)); |
| 576 | $group['node_'.$type.'_options']['relativity_child_query_'.$type.'_'.$chtype] = array( |
| 577 | '#type' => 'select', |
| 578 | '#title' => t('Use Relativity Query For Listing !chname Children', array('!chname'=>$chname)), |
| 579 | '#default_value' => variable_get('relativity_child_query_'.$type.'_'.$chtype, ''), |
| 580 | '#options' => $possible_queries, |
| 581 | '#description' => t('Use the specified relativity query to identify possible children.'), |
| 582 | ); |
| 583 | } |
| 584 | } |
| 585 | } |
| 586 | } |
| 587 | return system_settings_form($group); |
| 588 | } |
| 589 | |
| 590 | function relativity_display_settings() { |
| 591 | |
| 592 | $collapsed = (count(relativity_node_list()) == 1) ? FALSE : TRUE; |
| 593 | foreach(relativity_node_list() as $type=>$name) { |
| 594 | $group['node_'.$type.'_options'] = array( |
| 595 | '#type' => 'fieldset', |
| 596 | '#collapsible' => TRUE, |
| 597 | '#collapsed' => $collapsed, |
| 598 | '#description' => 'Here you can enter weights (positive or negative, integer or decimal) that determine where in the node body relativity links are displayed. Usually, the body has weight 0. For example, if you want Children Node links to appear at the top, enter -10.', |
| 599 | '#title' => t('Display options for !name (!type) nodes', array('!name'=>$name, '!type' =>$type)), |
| 600 | ); |
| 601 | |
| 602 | $group['node_'.$type.'_options']['relativity_'.$type.'_ancestor_weight'] = array( |
| 603 | '#type' => 'textfield', |
| 604 | '#title' => t('Ancestor nodes weight'), |
| 605 | '#description' => t('Enter 0 for no display'), |
| 606 | '#size' => 4, |
| 607 | '#maxlength' => 4, |
| 608 | '#default_value' => variable_get('relativity_'.$type.'_ancestor_weight', 0), |
| 609 | ); |
| 610 | |
| 611 | $group['node_'.$type.'_options']['relativity_'.$type.'_parents_weight'] = array( |
| 612 | '#type' => 'textfield', |
| 613 | '#title' => t('Parent nodes weight'), |
| 614 | '#description' => t('Enter 0 for no display'), |
| 615 | '#size' => 4, |
| 616 | '#maxlength' => 4, |
| 617 | '#default_value' => variable_get('relativity_'.$type.'_parents_weight', 10), |
| 618 | ); |
| 619 | |
| 620 | $group['node_'.$type.'_options']['relativity_'.$type.'_children_weight'] = array( |
| 621 | '#type' => 'textfield', |
| 622 | '#title' => t('Children nodes weight'), |
| 623 | '#description' => t('Enter 0 for no display'), |
| 624 | '#size' => 4, |
| 625 | '#maxlength' => 4, |
| 626 | '#default_value' => variable_get('relativity_'.$type.'_children_weight', 11), |
| 627 | ); |
| 628 | |
| 629 | $group['node_'.$type.'_options']['relativity_'.$type.'_operations_weight'] = array( |
| 630 | '#type' => 'textfield', |
| 631 | '#title' => t('Link operations weight'), |
| 632 | '#description' => t('Enter 0 for no display'), |
| 633 | '#size' => 4, |
| 634 | '#maxlength' => 4, |
| 635 | '#default_value' => variable_get('relativity_'.$type.'_operations_weight', 12), |
| 636 | ); |
| 637 | |
| 638 | |
| 639 | $render_opts = array( |
| 640 | 'title' => t('title only'), |
| 641 | 'teaser' => t('node teaser'), |
| 642 | 'body' => t('node body'), |
| 643 | 'hide' => t('hide this child type') |
| 644 | ); |
| 645 | |
| 646 | // allow user to choose a view to render a specifc |
| 647 | // child type |
| 648 | if (module_exists('views')) { |
| 649 | $views = array(); |
| 650 | $result = db_query("SELECT name FROM {view_view} ORDER BY name"); |
| 651 | while ($view = db_fetch_array($result)) { |
| 652 | $views[t('Existing Views')]['view:'.$view['name']] = $view['name']; |
| 653 | } |
| 654 | views_load_cache(); |
| 655 | $default_views = _views_get_default_views(); |
| 656 | foreach ($default_views as $view) { |
| 657 | $views[t('Default Views')]['view:'.$view->name] = $view->name; |
| 658 | } |
| 659 | $render_opts = array_merge($render_opts, $views); |
| 660 | } |
| 661 | |
| 662 | foreach (relativity_node_list() as $chtype=>$chname) { |
| 663 | if (in_array($chtype, variable_get('relativity_type_'.$type, array()))) { |
| 664 | $group['node_'.$type.'_options']['relativity_render_'.$type.'_'.$chtype] = array( |
| 665 | '#type' => 'select', |
| 666 | '#title' => t('Rendering option for children nodes of type !chname', array('!chname'=>$chname)), |
| 667 | '#default_value' => variable_get('relativity_render_'.$type.'_'.$chtype, 'title'), |
| 668 | '#options' => $render_opts, |
| 669 | ); |
| 670 | } |
| 671 | } |
| 672 | } |
| 673 | return system_settings_form($group); |
| 674 | } |
| 675 | |
| 676 | /** |
| 677 | * Implementation of hook_block(). |
| 678 | * |
| 679 | * Generates navigation block to quickly jump to any of this node's ancestors. |
| 680 | * See http://api.drupal.org/api/4.7/function/block_example_block |
| 681 | */ |
| 682 | function relativity_block($op = 'list', $delta = 0, $edit = array()) { |
| 683 | // The $op parameter determines what piece of information is being requested. |
| 684 | switch ($op) { |
| 685 | case 'list': |
| 686 | // If $op is "list", we just need to return a list of block descriptions. |
| 687 | // This is used to provide a list of possible blocks to the administrator, |
| 688 | // end users will not see these descriptions. |
| 689 | $blocks[0]['info'] = t('Node relativity: ancestors'); |
| 690 | $blocks[1]['info'] = t('Node relativity: children'); |
| 691 | $blocks[2]['info'] = t('Node relativity: parent'); |
| 692 | $blocks[3]['info'] = t('Node relativity: link operations'); |
| 693 | return $blocks; |
| 694 | |
| 695 | case 'configure': |
| 696 | // If $op is "configure", we need to provide the administrator with a |
| 697 | // configuration form. The $delta parameter tells us which block is being |
| 698 | // configured. |
| 699 | $form = array(); |
| 700 | switch($delta) { |
| 701 | case 0: // Ancestors block |
| 702 | $form['relativity_nav_types'] = array( |
| 703 | '#type' => 'select', |
| 704 | '#title' => t('Allowable Relativity Block Node types'), |
| 705 | '#default_value' => variable_get('relativity_nav_types', relativity_node_list()), |
| 706 | '#options' => relativity_node_list('none'), |
| 707 | '#description' => t('What node types are allowed to be used in this block?'), |
| 708 | '#size' => 5, |
| 709 | '#multiple' => TRUE, |
| 710 | ); |
| 711 | break; |
| 712 | } |
| 713 | |
| 714 | return $form; |
| 715 | |
| 716 | case 'save': |
| 717 | // If $op is "save", we need to save settings from the configuration form. |
| 718 | // Since the first block is the only one that allows configuration, we |
| 719 | // need to check $delta to make sure we only save it. |
| 720 | switch($delta) { |
| 721 | case 0; |
| 722 | variable_set('relativity_nav_types', $edit['relativity_nav_types']); |
| 723 | break; |
| 724 | } |
| 725 | return; |
| 726 | |
| 727 | case 'view': default: |
| 728 | // If $op is "view", then we need to generate the block for display |
| 729 | // purposes. The $delta parameter tells us which block is being requested. |
| 730 | |
| 731 | // see if we're viewing a node |
| 732 | if (arg(0) == 'node' && is_numeric(arg(1))) { |
| 733 | // see if it's a valid node |
| 734 | $node = node_load(arg(1)); |
| 735 | if (is_object($node) && node_access('view', $node)) { |
| 736 | switch ($delta) { |
| 737 | case 0: |
| 738 | $ancestors = relativity_load_ancestors($node,1,TRUE); |
| 739 | if (is_array($ancestors) && count($ancestors) > 0) { |
| 740 | $block = array('subject' => variable_get('relativity_ancestors_label', t('Related Ancestors')), |
| 741 | 'content' => theme('relativity_block_ancestors', $node, $ancestors), |
| 742 | ); |
| 743 | } |
| 744 | break; |
| 745 | case 1: |
| 746 | $content = theme('relativity_block_children', $node); |
| 747 | if ($content) { |
| 748 | $block = array('subject' => variable_get('relativity_children_label', t('Related Items')), |
| 749 | 'content' => $content, |
| 750 | ); |
| 751 | } |
| 752 | break; |
| 753 | case 2: |
| 754 | $content = theme('relativity_block_parents', $node); |
| 755 | if ($content) { |
| 756 | $block = array('subject' => variable_get('relativity_parents_label', t('Related Parents')), |
| 757 | 'content' => $content, |
| 758 | ); |
| 759 | } |
| 760 | break; |
| 761 | case 3: |
| 762 | $content = theme('relativity_block_link_operations', $node); |
| 763 | if ($content) { |
| 764 | $block = array('subject' => variable_get('relativity_actions_label', t('Link operations')), |
| 765 | 'content' => $content, |
| 766 | ); |
| 767 | } |
| 768 | break; |
| 769 | } |
| 770 | } |
| 771 | } |
| 772 | return $block; |
| 773 | } |
| 774 | } |
| 775 | |
| 776 | /** |
| 777 | * Generate an array of ancestors for the given node. |
| 778 | * This will keep looking for more ancestors until a circular path was found, |
| 779 | * if a node has multiple or no parents at all. |
| 780 | * If $load_multi_parent is true, the first multi-parent result found will be placed |
| 781 | * in the output array as an array of nodes. Otherwise, all array elements will be nodes. |
| 782 | */ |
| 783 | function relativity_load_ancestors($node, $load_multi_parent=1, $block=FALSE) { |
| 784 | $search_max = 5; // make this a settings variable someday |
| 785 | if (is_numeric($node->nid)) { |
| 786 | $ancestors = array(); |
| 787 | $nids = array(); |
| 788 | $search_nid = $node->nid; |
| 789 | $cnt = 0; |
| 790 | $allowed_types = variable_get('relativity_allow_types', array()); |
| 791 | if ($block == TRUE) { |
| 792 | $allowed_types = variable_get('relativity_nav_types', $allowed_types); |
| 793 | } |
| 794 | |
| 795 | do { |
| 796 | $keep_going = 0; |
| 797 | $result = db_query("SELECT parent_nid from {relativity} where nid=%d", $search_nid); |
| 798 | $parent_count = db_num_rows($result); |
| 799 | if ($parent_count == 1 && $obj = db_fetch_object($result)) { |
| 800 | // make sure we're not pursuing a circular path and that we stop at $search_max parents |
| 801 | if (!in_array($obj->parent_nid, $nids) && $cnt++ < $search_max) { |
| 802 | //drupal_set_message("unshifting node ".$obj->parent_nid." onto the ancestors array"); |
| 803 | $parent_node = node_load($obj->parent_nid); |
| 804 | if (node_access('view', $parent_node) && in_array($parent_node->type, $allowed_types)) { |
| 805 | array_unshift($ancestors, $parent_node); |
| 806 | $nids[] = $obj->parent_nid; |
| 807 | $search_nid = $obj->parent_nid; |
| 808 | $keep_going = 1; |
| 809 | } |
| 810 | } |
| 811 | } |
| 812 | elseif($parent_count > 1 && $load_multi_parent && $cnt++ < $search_max) { |
| 813 | //drupal_set_message("found parent_count == $parent_count, about to add array to ancestors array"); |
| 814 | // perhaps upon encountering multiple parents, it would suffice to print them |
| 815 | // all out at the same level and not follow any of them up, but still allow |
| 816 | // the user to navigate up whatever hierarchy they want to. |
| 817 | $siblings = array(); |
| 818 | while($obj = db_fetch_object($result)) { |
| 819 | // make an array of nodes to display at this level |
| 820 | $parent_node = node_load($obj->parent_nid); |
| 821 | if (!in_array($obj->parent_nid, $nids) && node_access('view', $parent_node) && in_array($parent_node->type, $allowed_types)) { |
| 822 | array_unshift($siblings, $parent_node); |
| 823 | $nids[] = $obj->parent_nid; |
| 824 | $search_nid = $obj->parent_nid; // only used when single result is rendered. |
| 825 | } |
| 826 | } |
| 827 | if (count($siblings) > 0) { |
| 828 | array_unshift($ancestors, $siblings); |
| 829 | } |
| 830 | if (count($siblings) == 1) { |
| 831 | $keep_going = 1; |
| 832 | } |
| 833 | } |
| 834 | } while($keep_going); |
| 835 | return $ancestors; |
| 836 | } |
| 837 | } |
| 838 | |
| 839 | /** |
| 840 | * Determines if the specified parent node may add a child of type $type. |
| 841 | * @return true if possible, false otherwise. |
| 842 | */ |
| 843 | function relativity_may_add_child($parent, $type) { |
| 844 | $common_children_reqd = variable_get('relativity_common_child_'.$parent->type.'_'.$type, array()); |
| 845 | if (count($common_children_reqd)) { |
| 846 | // NOTE: all of this needs node_access logic applied at the SQL level. Currently, if unreadable relationships fill the need, they allow this to pass through |
| 847 | |
| 848 | // lookup all existing children and see if any of them are on the common_children_reqd list |
| 849 | $result = db_query("SELECT n.nid as nid FROM {node} n INNER JOIN {relativity} r ON n.nid=r.nid WHERE r.parent_nid = %d AND n.type IN ('".implode("','", $common_children_reqd)."')", $parent->nid); |
| 850 | while($child = db_fetch_object($result)) { |
| 851 | $children[] = $child->nid; |
| 852 | } |
| 853 | // no common children defined for the parent, reject the request |
| 854 | if (!$children || !is_array($children) || !count($children)) { |
| 855 | return false; |
| 856 | } |
| 857 | |
| 858 | // now, see if any of the children that were found have a parent of type $type |
| 859 | $children = implode(',', $children); |
| 860 | $result = db_query("SELECT count(n.nid) as cnt FROM {node} n INNER JOIN {relativity} r ON n.nid=r.parent_nid WHERE r.nid IN ($children) AND n.type='%s'", $type); |
| 861 | $count = db_result($result); |
| 862 | if (!$count) { |
| 863 | return false; |
| 864 | } |
| 865 | } |
| 866 | |
| 867 | $ord = variable_get('relativity_child_ord_'.$parent->type.'_'.$type, 'any'); |
| 868 | if ($ord == 'any') { |
| 869 | return true; |
| 870 | } |
| 871 | else { |
| 872 | // look up how many children this parent currently has of the specified type |
| 873 | $res = db_fetch_object(db_query("SELECT count(n.nid) as cnt FROM {node} n INNER JOIN {relativity} r ON n.nid=r.nid WHERE r.parent_nid = %d AND n.type='%s'", $parent->nid, $type)); |
| 874 | if ($res->cnt >= $ord) { |
| 875 | return false; |
| 876 | } |
| 877 | else { |
| 878 | return true; |
| 879 | } |
| 880 | } |
| 881 | } |
| 882 | |
| 883 | /** |
| 884 | * Convenience function for determining if a node requires a parent to exist. |
| 885 | */ |
| 886 | function relativity_requires_parent($node) { |
| 887 | if (is_object($node)) { |
| 888 | $type = $node->type; |
| 889 | } |
| 890 | else { |
| 891 | $type = $node; |
| 892 | } |
| 893 | if (variable_get("relativity_parent_ord_$type", '') == 'one' || |
| 894 | variable_get("relativity_parent_ord_$type", '') == 'one or more') { |
| 895 | return true; |
| 896 | } |
| 897 | |
| 898 | return false; |
| 899 | } |
| 900 | |
| 901 | /** |
| 902 | * Convenience function for determining if a node may have more than one parent. |
| 903 | */ |
| 904 | function relativity_multi_parent($node) { |
| 905 | if (is_object($node)) { |
| 906 | $type = $node->type; |
| 907 | } |
| 908 | else { |
| 909 | $type = $node; |
| 910 | } |
| 911 | if (variable_get("relativity_parent_ord_$type", '') == 'any' || |
| 912 | variable_get("relativity_parent_ord_$type", '') == 'one or more') { |
| 913 | return true; |
| 914 | } |
| 915 | return false; |
| 916 | } |
| 917 | |
| 918 | /** |
| 919 | * If this node is required to connect a series of nodes together, return FALSE |
| 920 | */ |
| 921 | function relativity_may_unchild($parent, $child) { |
| 922 | |
| 923 | if (!node_access('update', $parent)) { |
| 924 | return FALSE; |
| 925 | } |
| 926 | |
| 927 | // check all possible child types for this parent |
| 928 | foreach (node_get_types('names') as $type=>$name) { |
| 929 | $conduit_types = variable_get('relativity_common_child_'.$parent->type.'_'.$type, array()); |
| 930 | if (in_array($child->type, $conduit_types)) { |
| 931 | // make sure no child nodes of type $type exist with $child as a child, as they would require $child here to exist. |
| 932 | $result = db_query("SELECT DISTINCT n.nid as nid FROM {node} n INNER JOIN {relativity} r ON n.nid=r.nid WHERE n.type = '%s' AND r.parent_nid = %d", $type, $parent->nid); |
| 933 | if (db_num_rows($result) > 0) { |
| 934 | return FALSE; |
| 935 | } |
| 936 | } |
| 937 | } |
| 938 | return TRUE; |
| 939 | } |
| 940 | |
| 941 | /** |
| 942 | * See if current user may create a *new* child of type $child_type to a parent of type $parent_type |
| 943 | */ |
| 944 | function relativity_may_attach_new_child_type($parent_type, $child_type) { |
| 945 | if (node_access('create', $child_type)) { |
| 946 | // make sure relationship is still valid |
| 947 | if (in_array($child_type, variable_get('relativity_type_'.$parent_type, array()))) { |
| 948 | // make sure relatinship doesn't require a common child |
| 949 | if (!variable_get('relativity_common_child_'.$parent_type.'_'.$child_type, FALSE)) { |
| 950 | return TRUE; |
| 951 | } |
| 952 | } |
| 953 | else { |
| 954 | return TRUE; |
| 955 | } |
| 956 | } |
| 957 | return FALSE; |
| 958 | } |
| 959 | |
| 960 | /** |
| 961 | * Deletes all rows involving the specified node from the database table |
| 962 | */ |
| 963 | function relativity_delete_relationships($node) { |
| 964 | // look to see if this is a required common child that is currently holding relationships together |
| 965 | foreach (node_get_types('names') as $ptype=>$pname) { |
| 966 | foreach (node_get_types('names') as $chtype=>$chname) { |
| 967 | // make sure that the parent/child relationship is still valid |
| 968 | if (in_array($chtype, variable_get('relativity_type_'.$ptype, array()))) { |
| 969 | |
| 970 | $conduit_types = variable_get('relativity_common_child_'.$ptype.'_'.$chtype, array()); |
| 971 | if (in_array($node->type, $conduit_types)) { |
| 972 | //drupal_set_message("deleting conduit node of type $node->type. See if there are any dependent $chtype relatives that are children of $ptype nodes"); |
| 973 | // find all children of type $chtype of this node's parents of type $ptype |
| 974 | $dependent_children = relativity_list_grand_relatives($node, 'parent', 'child', array($ptype), array($chtype), FALSE); |
| 975 | if (is_array($dependent_children) && count($dependent_children)) { |
| 976 | $dependent_children[$node->nid] = $node->nid; // include self in children filter |
| 977 | |
| 978 | // find their parents of type $ptype |
| 979 | $result = db_query("SELECT DISTINCT n.nid as nid FROM {node} n INNER JOIN {relativity} r ON n.nid=r.parent_nid WHERE n.type = '%s' AND r.nid IN (".implode(',', array_keys($dependent_children)).")", $ptype); |
| 980 | while($obj = db_fetch_object($result)) { |
| 981 | // if this potentially dependent parent also has $node as a child, delete it |
| 982 | if (db_result(db_query("SELECT count(r.nid) as cnt FROM {relativity} r WHERE r.parent_nid=%d AND r.nid=%d", $obj->nid, $node->nid))) { |
| 983 | $dependent_parents[] = $obj->nid; |
| 984 | } |
| 985 | } |
| 986 | if (is_array($dependent_parents) && count($dependent_parents)) { |
| 987 | drupal_set_message(t('Removing dependent children (%children) from dependent parents (%parents)', array('%children'=>implode(',', array_keys($dependent_children)), '%parents'=>implode(',', $dependent_parents)))); |
| 988 | // delete any relationships that require these $dependent_parents to have these $dependent_children |
| 989 | db_query("DELETE FROM {relativity} WHERE parent_nid IN (".implode(',', $dependent_parents).") AND nid IN (".implode(',', array_keys($dependent_children)).")"); |
| 990 | } |
| 991 | } |
| 992 | } |
| 993 | } |
| 994 | } |
| 995 | } |
| 996 | // clear out all relationships directly involving this node |
| 997 | db_query('DELETE FROM {relativity} WHERE nid = %d OR parent_nid = %d', $node->nid, $node->nid); |
| 998 | } |
| 999 | |
| 1000 | /** |
| 1001 | * Implementation of hook_nodeapi(). |
| 1002 | * |
| 1003 | * This hook allows us to act on all major node operations, |
| 1004 | * so we can manage our additional data appropriately. |
| 1005 | */ |
| 1006 | function relativity_nodeapi(&$node, $op, $teaser, $page) { |
| 1007 | if ($_GET['parent_node']) { |
| 1008 | $node->parent_node = $_GET['parent_node'] + 0; |
| 1009 | } |
| 1010 | elseif($_POST['parent_node']) { |
| 1011 | $node->parent_node = $_POST['parent_node'] + 0; |
| 1012 | } |
| 1013 | |
| 1014 | switch ($op) { |
| 1015 | |
| 1016 | case 'validate': |
| 1017 | if ($node->nid && ($_GET['parent_node'] || $_POST['parent_node'])) { |
| 1018 | $parents = explode(',', $node->parent_node); |
| 1019 | foreach($parents as $parent_nid) { |
| 1020 | $parent = node_load($parent_nid); |
| 1021 | if (!$parent || !in_array($node->type, variable_get('relativity_type_'. $parent->type, array()))) { |
| 1022 | form_set_error('relativity_type'.$node->type, t('You\'re not allowed to create this type of attachment.')); |
| 1023 | } |
| 1024 | } |
| 1025 | } |
| 1026 | break; |
| 1027 | |
| 1028 | case 'insert': |
| 1029 | if ($node->nid && $node->parent_node) { |
| 1030 | if (is_array($node->parent_node)) { |
| 1031 | foreach($node->parent_node as |