/[drupal]/contributions/modules/nodefamily/nodefamily.module
ViewVC logotype

Contents of /contributions/modules/nodefamily/nodefamily.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.32 - (show annotations) (download) (as text)
Thu Oct 4 08:53:34 2007 UTC (2 years, 1 month ago) by fago
Branch: MAIN
CVS Tags: HEAD
Changes since 1.31: +5 -2 lines
File MIME type: text/x-php
#179323: fixed warning: array_keys(): The first argument should be an array in nodefamily.module on line 426.
1 <?php
2 // $Id: nodefamily.module,v 1.31 2007/04/29 14:12:37 fago Exp $
3
4 /**
5 * @file
6 * Builds node families based on content types and author information
7 */
8
9
10 /**
11 * Implementation of hook_menu().
12 */
13 function nodefamily_menu($may_cache) {
14 $items = array();
15
16 if ($may_cache) {
17 $items[] = array(
18 'path' => 'admin/content/nodefamily',
19 'title' => t('Node family'),
20 'description' => t('Manage relations between content types.'),
21 'callback' => 'nodefamily_admin_page',
22 'access' => user_access('administer nodes'),
23 );
24 $items[] = array(
25 'path' => 'nodefamily',
26 'callback' => 'nodefamily_lonely_node_page_args',
27 'access' => user_access('access content'),
28 'type' => MENU_CALLBACK,
29 );
30 }
31 return $items;
32 }
33
34
35 /**
36 * Menu callback; provide the means to add and remove relations between
37 * content types.
38 */
39 function nodefamily_admin_page() {
40 $output = drupal_get_form('nodefamily_admin');
41 return $output . nodefamily_ct_relation_overview();
42 }
43
44 function nodefamily_admin() {
45 $typenames = node_get_types('names');
46
47 $form['add'] = array(
48 '#type' => 'fieldset',
49 '#title' => t('Add relation between content types'),
50 );
51 $form['add']['parent'] = array(
52 '#type' => 'select',
53 '#title' => t('Parent type'),
54 '#options' => $typenames,
55 '#required' => true,
56 );
57 $form['add']['child'] = array(
58 '#type' => 'select',
59 '#title' => t('Child type'),
60 '#options' => $typenames,
61 '#required' => true,
62 );
63 $form['add']['submit'] = array(
64 '#type' => 'submit',
65 '#value' => t('Add relation'),
66 '#weight' => 10,
67 );
68 return $form;
69 }
70
71 function nodefamily_admin_validate($form_id, &$form_values, &$form) {
72 if ($form_values['parent'] == $form_values['child']) {
73 form_set_error('child', t('You have to select two different content types.'));
74 }
75
76 $relations = variable_get('nodefamily_relations',array());
77 if (nodefamily_check_cycle($form_values['parent'], $form_values['child'], $relations)) {
78 form_set_error('child', t('You must not add this relation as it would result in a loop.'));
79 }
80 }
81
82 function nodefamily_admin_submit($form_id, &$form_values) {
83 nodefamily_ct_relation_add($form_values['parent'], $form_values['child']);
84 }
85
86
87 /**
88 * Determine if adding the relation between parent and child would
89 * result in a cycle.
90 */
91 function nodefamily_check_cycle($parent, $child, &$relations) {
92
93 //if we manage to reach the parent from the child, we would have a cycle
94 if (!array_key_exists($child, $relations)) {
95 return false;
96 }
97 else {
98 $new_relatives = array($child);
99 $all_relatives = array();
100 do {
101 $all_relatives = array_merge($all_relatives, $new_relatives);
102 $relatives = $new_relatives; //this relatives will be checked for new ones
103 $new_relatives = array();
104 foreach ($relatives as $related) {
105 if (array_key_exists($related, $relations)) {
106 foreach ($relations[$related] as $new_related => $array) {
107 $new_relatives[] = $new_related;
108 }
109 }
110 }
111 }
112 while ($new_relatives);
113 //finding all relatives done, is the parent in there?
114 return in_array($parent, $all_relatives);
115 }
116 }
117
118 /**
119 * Display the existing content type relations in a table.
120 */
121 function nodefamily_ct_relation_overview() {
122 $relations = variable_get('nodefamily_relations',array());
123 if (!$relations) {
124 return '';
125 }
126
127 if (arg(3) && arg(4)) {
128 // delete the relation
129 nodefamily_ct_relation_remove(arg(3), arg(4));
130 drupal_goto('admin/content/nodefamily');
131 }
132
133 $header = array(t('Parent type'), t('Child type'), '');
134 $rows = array();
135 $typenames = node_get_types('names');
136 foreach($relations as $key => $value) {
137 $rows = array_merge($rows, _nodefamily_relation_overview_dive($key, $value, $typenames));
138 }
139
140 return theme('table', $header, $rows, array('class' => 'nodefamily'));
141 }
142
143 function _nodefamily_relation_overview_dive($parent, $array, $typenames) {
144 $rows = array();
145 foreach($array as $key => $value) {
146 $rows[] = array($typenames[$parent], $typenames[$key],
147 l(t('delete'),'admin/content/nodefamily/' . $parent .'/'. $key));
148 if ($value && is_array($value)) {
149 $rows = array_merge($rows, _nodefamily_relation_overview_dive($key, $value, $typenames));
150 }
151 }
152 return $rows;
153 }
154
155
156
157
158 /**
159 * Implementation of hook_nodeapi().
160 */
161 function nodefamily_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
162
163 switch($op) {
164 case 'insert':
165 $parents = nodefamily_get_parent_types($node->type);
166 $children = nodefamily_get_child_types($node->type);
167
168 if ($parents) {
169 foreach ($parents as $parent_typename) {
170 nodefamily_relatives_set_parent($parent_typename, $node->uid, $node);
171 }
172 }
173 if ($children) {
174 foreach ($children as $child_typename) {
175 nodefamily_relatives_set_child($node, $child_typename, $node->uid);
176 }
177 }
178 break;
179
180 case 'delete':
181 nodefamily_relation_remove_parents($node);
182 nodefamily_relation_remove_children($node);
183 break;
184
185 case 'validate':
186 if (!$node->nid && user_access('administer nodes')) {
187 if ($account = user_load(array('name' => $node->name))) {
188 $node->uid = $account->uid;
189 }
190 else {
191 $node->uid = 0;
192 }
193 }
194
195 if (!$node->nid && nodefamily_content_type_is_max($node->type, $node->uid)) {
196 form_set_error('name', t("You can't create more nodes of this type for this user."));
197 $form = NULL;
198 }
199 break;
200 case 'submit':
201 if ($node->nid && user_access('administer nodes')) {
202 $parents = nodefamily_get_parent_types($node->type);
203 $children = nodefamily_get_child_types($node->type);
204 $oldnode = node_load($node->nid);
205 if ($oldnode->uid != $node->uid) {
206 //we have to update the relations because the node author changed
207 if ($parents) {
208 nodefamily_relation_remove_parents($node);
209 foreach ($parents as $parent_typename) {
210 nodefamily_relatives_set_parent($parent_typename, $node->uid, $node);
211 }
212 }
213 if ($children) {
214 nodefamily_relation_remove_children($node);
215 foreach ($children as $child_typename) {
216 nodefamily_relatives_set_child($node, $child_typename, $node->uid);
217 }
218 }
219 }
220 }
221 break;
222
223 default:
224 }
225 }
226
227 /**
228 * Implementation of hook_form_alter().
229 */
230 function nodefamily_form_alter($form_id, &$form) {
231 if ($form_id == 'node_type_form' &&
232 ( !module_exists('usernode') || $form['#node_type']->type != USERNODE_CONTENT_TYPE )) {
233
234 /* The 'nodefamily_max' field is in the workflow fieldset at the moment,
235 * because the buttons are not properly weighted.
236 * TODO: if node_type_form() in node's content_types.inc fixes this,
237 * we can think about switching back to our own block.
238 */
239 /*
240 $form['nodefamily'] = array(
241 '#type' => 'fieldset',
242 '#title' => t('Nodefamily'),
243 '#collapsible' => 1,
244 '#weight' => 30,
245 );*/
246 $form['workflow']['nodefamily_max'] = array(
247 '#type' => 'textfield',
248 '#title' => 'Maximum population',
249 '#size' => 4,
250 '#maxlength' => 4,
251 '#description' => t('Maximum number of nodes of this content type per user. Enter 0 for no limit.'),
252 '#required' => FALSE,
253 '#validate' => array('nodefamily_node_settings_validate' => array()),
254 '#default_value' => nodefamily_content_type_get_max($form['#node_type']->type),
255 );
256 }
257 else if (($form['#node_type']) && $form['#node_type']->type .'_node_form' == $form_id) {
258 $node = $form['#node'];
259 if (!$node->nid && !user_access('administer nodes') && nodefamily_content_type_is_max($node->type, $node->uid)) {
260 drupal_set_message(t("You can't create any more nodes of this type."), 'error');
261 $form = NULL;
262 }
263 }
264 }
265
266 function nodefamily_node_settings_validate(&$formelement) {
267 if (!is_numeric($formelement['#value'])) {
268 form_set_error($formelement['#parents'][0], t('Entry must be an integer.'));
269 }
270 else if ($formelement['#value'] < 0) {
271 form_set_error($formelement['#parents'][0], t('Entry must be at least 0.'));
272 }
273 }
274
275 /**
276 * Set the maximum number of nodes of a content type per user (population).
277 */
278 function nodefamily_content_type_set_max($typename, $max) {
279 variable_set('nodefamily_max_'. $typename, $max);
280 }
281
282 /**
283 * Get the maximum number of nodes of a content type per user (population).
284 */
285 function nodefamily_content_type_get_max($typename) {
286 return variable_get('nodefamily_max_'. $typename, 0);
287 }
288
289 function _nodefamily_content_type_del_max($typename) {
290 variable_del('nodefamily_max_'. $typename);
291 }
292
293 /**
294 * Return, if the maximum population is already reached.
295 */
296 function nodefamily_content_type_is_max($typename, $uid) {
297 $max = nodefamily_content_type_get_max($typename);
298 if ($max == 0 || $uid == 0) {
299 return FALSE;
300 }
301 $result = db_query("SELECT COUNT(*) FROM {node} n WHERE uid = %d AND type = '%s'", $uid, $typename);
302 $count = db_result($result);
303 return $count == $max;
304 }
305
306 /**
307 * Implementation of hook_node_type():
308 * If a content type changes, rename or delete the concerned relations
309 * and the maximum population variable.
310 */
311 function nodefamily_node_type($op, $info) {
312 switch ($op){
313 case 'delete':
314 _nodefamily_content_type_del_max($info->type); // maximum population
315 nodefamily_ct_relation_remove_all($info->type); // relations
316 break;
317 case 'update':
318 if (!empty($info->old_type) && $info->old_type != $info->type) {
319 // maximum population
320 $type_max_population = variable_get('nodefamily_max_'. $info->old_type, -1);
321 if ($type_max_population != -1) {
322 _nodefamily_content_type_del_max($info->old_type);
323 nodefamily_content_type_set_max($info->type, $type_max_population);
324 }
325
326 // relations
327 foreach (nodefamily_get_parent_types($info->old_type) as $parent_typename) {
328 nodefamily_ct_relation_remove($parent_typename, $info->old_type);
329 nodefamily_ct_relation_add($parent_typename, $info->type);
330 }
331 foreach (nodefamily_get_child_types($info->old_type) as $child_typename) {
332 nodefamily_ct_relation_remove($info->old_type, $child_typename);
333 nodefamily_ct_relation_add($info->type, $child_typename);
334 }
335 }
336 break;
337 }
338 }
339
340
341 /**
342 * @defgroup nodefamily_ct_relation Implementation of content type relation API
343 * @{
344 */
345
346 /**
347 * Add a relation between content types.
348 */
349 function nodefamily_ct_relation_add($parent_typename, $child_typename) {
350
351 $relations = variable_get('nodefamily_relations', array());
352
353 if (array_key_exists($parent_typename, $relations)) {
354 $relations[$parent_typename][$child_typename] = array();
355 }
356 else {
357 $relations[$parent_typename] = array($child_typename => array());
358 }
359 variable_set('nodefamily_relations', $relations);
360
361 // add node-node relations
362 nodefamily_relation_add_by_type($parent_typename, $child_typename);
363 }
364
365 /**
366 * Remove a relation between content types.
367 */
368 function nodefamily_ct_relation_remove($parent_typename, $child_typename) {
369
370 $relations = variable_get('nodefamily_relations', array());
371 if (array_key_exists($parent_typename, $relations)) {
372 unset($relations[$parent_typename][$child_typename]);
373 if (!$relations[$parent_typename]) {
374 unset($relations[$parent_typename]);
375 }
376 variable_set('nodefamily_relations', $relations);
377
378 // remove existing node relations
379 nodefamily_relation_remove_by_type($parent_typename, $child_typename);
380 }
381 }
382
383 /**
384 * Get all relations between content types.
385 */
386 function nodefamily_ct_get_relations() {
387
388 return variable_get('nodefamily_relations', array());
389 }
390
391 /**
392 * Remove all relations that involve the given content type.
393 */
394 function nodefamily_ct_relation_remove_all($typename) {
395 foreach (nodefamily_get_parent_types($typename) as $parent_typename) {
396 nodefamily_ct_relation_remove($parent_typename, $typename);
397 }
398 foreach (nodefamily_get_child_types($typename) as $child_typename) {
399 nodefamily_ct_relation_remove($typename, $child_typename);
400 }
401 }
402
403
404 /**
405 * Return an array of all parent content types for the given child content type.
406 */
407 function nodefamily_get_parent_types($typename = NULL) {
408 $relations = variable_get('nodefamily_relations', array());
409
410 $parent_typenames = array();
411 foreach($relations as $parent_typename => $children) {
412 if ($typename == NULL || in_array($typename, array_keys($children))) {
413 $parent_typenames[] = $parent_typename;
414 }
415 }
416 return $parent_typenames;
417 }
418
419 /**
420 * Return an array of all child content types for the given parent content type.
421 */
422 function nodefamily_get_child_types($typename = NULL) {
423 $relations = variable_get('nodefamily_relations', array());
424
425 if (array_key_exists($typename, $relations)) {
426 return array_keys($relations[$typename]);
427 }
428 else if ($typename == NULL) {
429 return array_keys(call_user_func_array('array_merge', $relations));
430 }
431 else {
432 return array();
433 }
434 }
435
436 /**
437 * Return an array of all ancestor content types for the given content type.
438 */
439 function nodefamily_get_ancestor_types($typename = NULL) {
440 $typenames = array();
441
442 foreach (nodefamily_get_parent_types($typename) as $parent) {
443 $typenames[] = $parent;
444 $typenames = array_merge($typenames, nodefamily_get_ancestor_types($parent));
445 }
446 return $typenames;
447 }
448
449 /**
450 * Return an array of all descendant content types for the given content type.
451 */
452 function nodefamily_get_descendant_types($typename = NULL) {
453 $typenames = array();
454
455 foreach (nodefamily_get_child_types($typename) as $child) {
456 $typenames[] = $child;
457 $typenames = array_merge($typenames, nodefamily_get_descendant_types($child));
458 }
459 return $typenames;
460 }
461
462
463 /**
464 * Set the node-node relation for all parent nodes
465 * with the type $parent_typename and the author uid $uid.
466 */
467 function nodefamily_relatives_set_parent($parent_typename, $uid, &$childnode) {
468
469 $result = db_query("SELECT nid FROM {node} WHERE uid=%d AND type='%s'",
470 $uid, $parent_typename);
471
472 while ($node = db_fetch_object($result)) {
473 nodefamily_relation_add($node, $childnode);
474 }
475 }
476
477 /**
478 * Set the node-node relation for all child nodes
479 * with the type $child_typename and the author uid $uid.
480 */
481 function nodefamily_relatives_set_child($parentnode, $child_typename, $uid) {
482
483 $result = db_query("SELECT nid FROM {node} WHERE uid=%d AND type='%s'",
484 $uid, $child_typename);
485
486 while ($node = db_fetch_object($result)) {
487 nodefamily_relation_add($parentnode, $node);
488 }
489 }
490
491 /**
492 * @} End of "defgroup nodefamily_ct_relation".
493 */
494
495
496
497
498 /**
499 * @defgroup nodefamily_relation Implementation of node - node relation API
500 * @{
501 */
502
503 function nodefamily_relation_add(&$parent_node, &$child_node) {
504
505 db_query("INSERT INTO {nodefamily} (parent_nid, child_nid) VALUES(%d, %d)",
506 $parent_node->nid, $child_node->nid);
507 }
508
509 function nodefamily_relation_remove(&$parent_node, &$child_node) {
510
511 db_query("DELETE FROM {nodefamily} WHERE parent_nid = %d AND child_nid = %d",
512 $parent_node->nid, $child_node->nid);
513 }
514
515 function nodefamily_relation_remove_children(&$parent_node) {
516
517 db_query("DELETE FROM {nodefamily} WHERE parent_nid = %d", $parent_node->nid);
518 }
519
520 function nodefamily_relation_remove_parents(&$child_node) {
521
522 db_query("DELETE FROM {nodefamily} WHERE child_nid = %d", $child_node->nid);
523 }
524
525 function nodefamily_relation_remove_by_type(&$parent_typename, &$child_typename) {
526
527 db_query("DELETE FROM {nodefamily} WHERE parent_nid IN ".
528 "(SELECT nid FROM {node} WHERE type ='%s') AND ".
529 "child_nid IN (SELECT nid FROM {node} WHERE type ='%s')",
530 $parent_typename, $child_typename);
531 }
532
533 function nodefamily_relation_add_by_type(&$parent_typename, &$child_typename) {
534
535 db_query("INSERT INTO {nodefamily} (parent_nid, child_nid) ".
536 "SELECT n1.nid,n2.nid FROM {node} n1 ".
537 "JOIN {node} n2 ON n2.type = '%s' ".
538 "LEFT JOIN {nodefamily} nf ON nf.parent_nid = n1.nid AND nf.child_nid = n2.nid ".
539 "WHERE n1.type = '%s' AND nf.parent_nid IS NULL AND n1.uid = n2.uid",
540 $child_typename, $parent_typename);
541 }
542
543 /**
544 * Load all children's nids for a node. This function doesn't obey node_access
545 * for the current user, it just loads all children.
546 * The children's node-ids will be loaded into the array $node->children.
547 *
548 * @param $node The node object or the node's id
549 */
550 function nodefamily_relation_load_all_nids(&$node) {
551
552 if (!is_object($node)) {
553 //$node is the nid
554 $node2 = node_load($node);
555 return is_object($node2) ? nodefamily_relation_load_all_nids($node2) : FALSE;
556 }
557
558 $result = db_query("SELECT child_nid FROM {nodefamily} WHERE parent_nid = %d", $node->nid);
559
560 $node->children = array();
561 while ($row = db_fetch_object($result)) {
562 $node->children[$row->child_nid] = $row->child_nid;
563 }
564 return $node->children;
565 }
566
567 /**
568 * Load all children for a node.
569 * The children's nodes will be loaded into the array $node->children.
570 *
571 * @param $node The node object or the node's id
572 * @param $status The minimum status value a node must have to be included. Use 0 for all nodes.
573 */
574 function nodefamily_relation_load(&$node, $status = 1) {
575
576 if (!is_object($node)) {
577 //$node is the nid
578 $node2 = node_load($node);
579 return is_object($node2) ? nodefamily_relation_load($node2, $status) : FALSE;
580 }
581
582 $result = db_query(db_rewrite_sql("SELECT n.nid FROM {node} n ".
583 "JOIN {nodefamily} nf ON nf.child_nid = n.nid WHERE nf.parent_nid = %d AND n.status >= %d ORDER BY n.nid"), $node->nid, $status);
584
585 $node->children = array();
586 while ($row = db_fetch_object($result)) {
587 if ($child = node_load($row->nid)) {
588 $node->children[] = $child;
589 }
590 }
591 return $node->children;
592 }
593
594
595 /**
596 * Load all children for a node, sorted by content type.
597 * The children's nodes will be loaded into the array $node->children
598 * which contains an array of children for each content type.
599 *
600 * @param $node The node object or the node's id
601 * @param $status The minimum status value a node must have to be included. Use 0 for all nodes.
602 */
603 function nodefamily_relation_load_by_type(&$node, $status = 1) {
604
605 if (!is_object($node)) {
606 //$node is the nid
607 $node2 = node_load($node);
608 return is_object($node2) ? nodefamily_relation_load_by_type($node2, $status) : FALSE;
609 }
610
611 $result = db_query(db_rewrite_sql("SELECT n.nid FROM {node} n ".
612 "JOIN {nodefamily} nf ON nf.child_nid = n.nid WHERE nf.parent_nid = %d AND n.status >= %d ORDER BY n.nid"), $node->nid, $status);
613
614 $node->children = array();
615 while ($row = db_fetch_object($result)) {
616 if ($child = node_load($row->nid)) {
617 $node->children[$child->type][] = $child;
618 }
619 }
620 return $node->children;
621 }
622
623 /**
624 * Load all parents for a node.
625 * The parent nodes will be loaded into the array $node->parents.
626 *
627 * @param $node The node object or the node's id
628 * @param $status The minimum status value a node must have to be included. Use 0 for all nodes.
629 */
630 function nodefamily_relation_load_parents(&$node, $status = 1) {
631
632 if (!is_object($node)) {
633 //$node is the nid
634 $node2 = node_load($node);
635 return is_object($node2) ? nodefamily_relation_load_parents($node2, $status) : FALSE;
636 }
637
638 $result = db_query(db_rewrite_sql("SELECT n.nid FROM {node} n ".
639 "JOIN {nodefamily} nf ON nf.parent_nid = n.nid WHERE nf.child_nid = %d AND n.status >= %d ORDER BY n.nid"), $node->nid, $status);
640
641
642 $node->parents = array();
643 while ($row = db_fetch_object($result)) {
644 if ($parent = node_load($row->nid)) {
645 $node->parents[] = $parent;
646 }
647 }
648 return $node->parents;
649 }
650
651
652 /**
653 * Load all siblings for a node.
654 * The sibling nodes will be loaded into the array $node->siblings and grouped by their parent.
655 *
656 * @param $node The node object or the node's id
657 * @param $status The minimum status value a node must have to be included. Use 0 for all nodes.
658 */
659 function nodefamily_relation_load_siblings(&$node, $status = 1) {
660
661 if (!is_object($node)) {
662 //$node is the nid
663 $node2 = node_load($node);
664 return is_object($node2) ? nodefamily_relation_load_siblings($node2, $status) : FALSE;
665 }
666 //load the parents
667 nodefamily_relation_load_parents($node, $status);
668 $node->siblings = array();
669 // find and load the children of the parents
670 foreach ($node->parents as $parent) {
671 $children = nodefamily_relation_load($parent->nid, $status);
672 foreach ($children as $child) {
673 // don't include current node in list of siblings
674 if ($child->nid != $node->nid) {
675 $node->siblings[][] = $child;
676 }
677 }
678 }
679 return $node->siblings;
680 }
681
682 /**
683 * @} End of "defgroup nodefamily_relation".
684 */
685
686
687
688 /**
689 * Provide a unique URL for adding/editing nodes of types
690 * with a maximum population of one.
691 */
692 function nodefamily_lonely_node_page_args() {
693
694 $types = node_get_types();
695 $typename = arg(1);
696
697 if (!$types[$typename] || nodefamily_content_type_get_max($typename) != 1) {
698 drupal_not_found();
699 exit;
700 }
701
702 $uid = (arg(2) && is_numeric(arg(2))) ? arg(2) : NULL;
703
704 return nodefamily_lonely_node_page($typename, $uid);
705 }
706
707
708 function nodefamily_lonely_node_page($typename, $uid = NULL) {
709 global $user;
710
711 $node = node_load(array('type' => $typename, 'uid' => $uid ? $uid : $user->uid));
712
713 if (!$node) {
714 // show add form
715 return node_add($typename);
716 }
717 else if (node_access('update', $node)) {
718 //show edit form
719 return node_page_edit($node);
720 }
721 drupal_not_found();
722 }
723
724
725
726 /**
727 * Pageroute integration
728 */
729
730 /**
731 * Implementation of hook_pageroute_info().
732 */
733 function nodefamily_pageroute_info() {
734 return array(
735 'manage_lonely' => array('name' => t('Lonely node management'), 'base' => 'nodefamily', 'default_target' => PAGEROUTE_FORWARD),
736 'view_lonely' => array('name' => t('Lonely node display'), 'base' => 'nodefamily'),
737 );
738 }
739
740 /*
741 * Implementation of pageroutes' hook_page()
742 */
743 function nodefamily_page_manage_lonely($route, $page, $form) {
744 $task = pageroute_page_arg($page, 0);
745 if ($task == 'delete') {
746 $page->arg_offset++; //the delete subpage is to be shown..
747 }
748 $node = node_load(array(
749 'type' => $page->options['content-type'],
750 'uid' => $uid = pageroute_page_get_uid($page),
751 ));
752 //do we need to show the delete confirm form?
753 if ($task == 'delete') {
754 return pageroute_node_delete_confirm($node, $page, $form);
755 }
756 //the node edit form page type will present an add form for us, if there is no node id
757 return pageroute_page_edit($route, $page, $form, $node->nid ? $node->nid : FALSE);
758 }
759
760 /*
761 * Implementation of pageroutes' hook_page()
762 */
763 function nodefamily_page_view_lonely($route, $page, $form) {
764 $node = node_load(array(
765 'type' => $page->options['content-type'],
766 'uid' => pageroute_page_get_uid($page),
767 ));
768 if ($node->nid && node_access('view', $node)) {
769 $page->options['nid'] = $node->nid;
770 return pageroute_page_view($route, $page, $form);
771 }
772 else {
773 $type_name = node_get_types('name', $page->options['content-type']);
774 $form['empty'] = array('#value' => theme('nodefamily_lonely_node_view_empty', $type_name));
775 return $form;
776 }
777 }
778
779 function theme_nodefamily_lonely_node_view_empty($type_name) {
780 return '<div class="nodefamily-empty">'.
781 t('You have not created a @type yet. Go ahead and create one!', array('@type' => $type_name)) .'</div>';
782 }
783
784 /*
785 * Implementations of hook_page_ui().
786 */
787 function nodefamily_page_view_lonely_ui($route, $page, &$form, $type) {
788 $form['options']['content-type'] = array(
789 '#type' => 'select',
790 '#title' => t('content type'),
791 '#options' => nodefamily_lonely_node_types(),
792 '#required' => TRUE,
793 '#default_value' => $page->options['content-type'],
794 '#weight' => 2,
795 '#description' => t('You can only use content types with a maximum '.
796 'nodefamily population set to one!'),
797 );
798 }
799 function nodefamily_page_manage_lonely_ui($route, $page, &$form, $type) {
800 nodefamily_page_view_lonely_ui($route, $page, $form, $type);
801 pageroute_pages_node_ui($route, $page, $form, $type);
802 }
803
804 /*
805 * Returns an array of lonely node types
806 */
807 function nodefamily_lonely_node_types($op = 'names') {
808 $types = node_get_types($op);
809 $lonely_node_types = array();
810 foreach($types as $typename => $type) {
811 if (nodefamily_content_type_get_max($typename) == 1) {
812 $lonely_node_types[$typename] = $type;
813 }
814 }
815 return $lonely_node_types;
816 }
817
818 /*
819 * Implementations of hook_page_help().
820 */
821 function nodefamily_page_manage_lonely_help() {
822 return t('The "lonely" page types may be used only with content types, '.
823 'which are restricted to a maximum population of one by the '.
824 'nodefamily module. Then you can use the lonely node '.
825 'management page to add/edit the "lonely node" as it might be '.
826 'useful e.g. for user profiles.');
827 }
828 function nodefamily_page_view_lonely_help() {
829 return t('The lonely node display page can be used to view this lonely '.
830 'node. This might be useful for displaying the lonely node after'.
831 'creation or update. There will be '.
832 'a (themeable) message if there is no node that can be displayed.');
833 }
834
835
836 /**
837 * Views integration
838 */
839
840 /**
841 * Implementation of hook_views_fusion().
842 */
843 function nodefamily_views_fusion() {
844
845 return array('nodefamily_parent' => array(
846 'title' => t('nodefamily relation: parent - child'),
847 'field' => 'child_nid',
848 ),
849 'nodefamily_child' => array(
850 'title' => t('nodefamily relation: child - parent'),
851 'field' => 'parent_nid',
852 ),
853 );
854 }
855
856 function nodefamily_views_tables() {
857 $tables['nodefamily_parent'] = array(
858 'name' => 'nodefamily',
859 'join' => array(
860 'left' => array(
861 'table' => 'node',
862 'field' => 'nid',
863 ),
864 'right' => array(
865 'field' => 'parent_nid'
866 ),
867 'type' => 'inner',
868 ),
869 'filters' => array(
870 'child_nid' => array(
871 'name' => t('Nodefamily: Child Node ID'),
872 'operator' => 'views_handler_operator_eqneq',
873 'option' => array(
874 '#type' => 'select',
875 '#options' => node_get_types('names'),
876 ),
877 'handler' => 'nodefamily_views_filter',
878 'help' => t('This allows you to filter by child node ID.').t('You can optionally restrict the filter to a certain content type, which makes sense to use in conjunctions with the NOT EQUAL operator.'),
879 ),
880 ),
881 );
882 $tables['nodefamily_child'] = array(
883 'name' => 'nodefamily',
884 'join' => array(
885 'left' => array(
886 'table' => 'node',
887 'field' => 'nid',
888 ),
889 'right' => array(
890 'field' => 'child_nid'
891 ),
892 'type' => 'inner',
893 ),
894 'filters' => array(
895 'parent_nid' => array(
896 'name' => t('Nodefamily: Parent Node ID'),
897 'operator' => 'views_handler_operator_eqneq',
898 'option' => array(
899 '#type' => 'select',
900 '#options' => node_get_types('names'),
901 ),
902 'handler' => 'nodefamily_views_filter',
903 'help' => t('This allows you to filter by parent node ID.').t('You can optionally restrict the filter to a certain content type, which makes sense to use in conjunctions with the NOT EQUAL operator.'),
904 ),
905 ),
906 );
907 // these tables are used for the above filters to join the node table again
908 $tables['nf_node_child'] = array(
909 'name' => 'node',
910 'join' => array(
911 'left' => array(
912 'table' => 'nodefamily_parent',
913 'field' => 'child_nid',
914 ),
915 'right' => array(
916 'field' => 'nid'
917 ),
918 'type' => 'inner',
919 ),
920 );
921 $tables['nf_node_parent'] = array(
922 'name' => 'node',
923 'join' => array(
924 'left' => array(
925 'table' => 'nodefamily_child',
926 'field' => 'parent_nid',
927 ),
928 'right' => array(
929 'field' => 'nid'
930 ),
931 'type' => 'inner',
932 ),
933 );
934 return $tables;
935 }
936
937
938 function nodefamily_views_arguments() {
939 $arguments = array(
940 'parent_nid' => array(
941 'name' => t('Nodefamily: Parent ID'),
942 'handler' => 'nodefamily_views_handler_arg_parent_nid',
943 'help' => t('This argument is the Node ID of the parent node of a node.'),
944 ),
945 'child_nid' => array(
946 'name' => t('Nodefamily: Child ID'),
947 'handler' => 'nodefamily_views_handler_arg_child_nid',
948 'help' => t('This argument is the Node ID of the child node of a node.'),
949 ),
950 'grandchild_nid' => array(
951 'name' => t('Nodefamily: Grandchild ID'),
952 'handler' => 'nodefamily_views_handler_arg_grand_child_nid',
953 'help' => t('This argument is the Node ID of a grandchild node of a node.'),
954 ),
955 'grandparent_nid' => array(
956 'name' => t('Nodefamily: Grandparent ID'),
957 'handler' => 'nodefamily_views_handler_arg_grand_parent_nid',
958 'help' => t('This argument is the Node ID of a grandparent node of a node.'),
959 ),
960 );
961 return $arguments;
962 }
963
964
965 function nodefamily_views_handler_arg_parent_nid($op, &$query, $argtype, $arg = '') {
966 switch($op) {
967 case 'summary':
968 // do nothing. field name parent_nid makes troubles...
969 break;
970 case 'sort':
971 $query->add_orderby('nodefamily', 'parent_nid', $argtype);
972 break;
973 case 'filter':
974 $num = $query->add_table('nodefamily_child');
975 $tablename = $query->get_table_name('nodefamily_child', $num);
976 $query->add_where($tablename. ".parent_nid = %d", $arg);
977 break;
978 case 'link':
979 return l($query->parent_nid, "$arg/$query->parent_nid");
980 case 'title':
981 $node = db_fetch_object(db_query("SELECT title FROM {node} WHERE nid=%d", $query));
982 return check_plain($node->title);
983 }
984 }
985
986
987 function nodefamily_views_handler_arg_child_nid($op, &$query, $argtype, $arg = '') {
988 switch($op) {
989 case 'summary':
990 // do nothing. field name child_nid makes troubles...
991 break;
992 case 'sort':
993 $query->add_orderby('nodefamily', 'child_nid', $argtype);
994 break;
995 case 'filter':
996 $num = $query->add_table('nodefamily_parent');
997 $tablename = $query->get_table_name('nodefamily_parent', $num);
998 $query->add_where($tablename. ".child_nid = %d", $arg);
999 break;
1000 case 'link':
1001 return l($query->child_nid, "$arg/$query->child_nid");
1002 case 'title':
1003 $node = db_fetch_object(db_query("SELECT title FROM {node} WHERE nid=%d", $query));
1004 return check_plain($node->title);
1005 }
1006 }
1007
1008 function nodefamily_views_handler_arg_grand_child_nid($op, &$query, $argtype, $arg = '') {
1009 switch($op) {
1010 case 'summary':
1011 // do nothing. field name child_nid makes troubles...
1012 break;
1013 case 'sort':
1014 $query->add_orderby('nodefamily', 'child_nid', $argtype);
1015 break;
1016 case 'filter':
1017 $table_data = _views_get_tables();
1018 $num = $query->add_table('nodefamily_parent');
1019 // join again the nodefamily table
1020 $joininfo = $table_data['nodefamily_parent']['join'];
1021 $joininfo['left']['table'] = $query->get_table_name('nodefamily_parent', $num);
1022 $joininfo['left']['field'] = 'child_nid';
1023 $num = $query->add_table('nodefamily_parent', false, 1, $joininfo);
1024 $tablename = $query->get_table_name('nodefamily_parent', $num);
1025 $query->add_where($tablename. ".child_nid = %d", $arg);
1026 break;
1027 case 'link':
1028 return l($query->child_nid, "$arg/$query->child_nid");
1029 case 'title':
1030 $node = db_fetch_object(db_query("SELECT title FROM {node} WHERE nid=%d", $query));
1031 return check_plain($node->title);
1032 }
1033 }
1034
1035 function nodefamily_views_handler_arg_grand_parent_nid($op, &$query, $argtype, $arg = '') {
1036 switch($op) {
1037 case 'summary':
1038 // do nothing. field name child_nid makes troubles...
1039 break;
1040 case 'sort':
1041 $query->add_orderby('nodefamily', 'parent_nid', $argtype);
1042 break;
1043 case 'filter':
1044 $table_data = _views_get_tables();
1045 $num = $query->add_table('nodefamily_child');
1046 // join again the nodefamily table
1047 $joininfo = $table_data['nodefamily_child']['join'];
1048 $joininfo['left']['table'] = $query->get_table_name('nodefamily_child', $num);
1049 $joininfo['left']['field'] = 'parent_nid';
1050 $num = $query->add_table('nodefamily_child', false, 1, $joininfo);
1051 $tablename = $query->get_table_name('nodefamily_child', $num);
1052 $query->add_where($tablename. ".parent_nid = %d", $arg);
1053 break;
1054 case 'link':
1055 return l($query->parent_nid, "$arg/$query->parent_nid");
1056 case 'title':
1057 $node = db_fetch_object(db_query("SELECT title FROM {node} WHERE nid=%d", $query));
1058 return check_plain($node->title);
1059 }
1060 }
1061
1062
1063 function nodefamily_views_filter($op, $filter, $filterinfo, &$query) {
1064 $query->ensure_table($filterinfo['table']);
1065 $query->add_where("%s.%s %s '%s'", $filterinfo['table'], $filterinfo['field'], $filter['operator'], $filter['value']);
1066
1067 if ($filter['options']) {
1068 $table = ($filterinfo['table'] == 'nodefamily_child') ? 'nf_node_parent' : 'nf_node_child';
1069 $num = $query->add_table($table);
1070 $tablename = $query->get_table_name($table, $num);
1071 $query->add_where("%s.type = '%s'", $tablename, $filter['options']);
1072 }
1073 }

  ViewVC Help
Powered by ViewVC 1.1.2