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

Contents of /contributions/modules/pageroute/pageroute.module

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


Revision 1.71 - (show annotations) (download) (as text)
Tue Nov 6 15:53:10 2007 UTC (2 years ago) by fago
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-6--1
Changes since 1.70: +3 -2 lines
File MIME type: text/x-php
ensure that the unique form id of each pageroute form is valid
1 <?php
2 // $Id: pageroute.module,v 1.70 2007/11/05 12:37:56 fago Exp $
3
4 /**
5 * @file
6 * Allows the creation of pageroutes.
7 */
8
9 /*
10 * some defines used for determing the redirect target
11 */
12 define('PAGEROUTE_BACK', -1);
13 define('PAGEROUTE_CURRENT', 0);
14 define('PAGEROUTE_FORWARD', 1);
15 define('PAGEROUTE_NONE', FALSE);
16 /*
17 * tabs config defines
18 */
19 define('PAGEROUTE_BUTTON_TABS', 1);
20 define('PAGEROUTE_MENU_TABS', 2);
21
22 // include own page type implementations
23 include_once(drupal_get_path('module', 'pageroute') .'/pageroute_pages.inc');
24
25 /*
26 * Get a list of all pageroute page types.
27 * @param $op One of list, base, or all.
28 */
29 function pageroute_get_types($op = 'list') {
30 static $type_list, $type_base, $types;
31
32 if (!isset($type_list)) {
33 $page_types = module_invoke_all('pageroute_info');
34 foreach ($page_types as $type_id => $type) {
35 $type_list[$type_id] = $type['name'];
36 $type_base[$type_id] = $type['base'];
37 $types[$type_id] = $type;
38 }
39 }
40 switch ($op) {
41 case 'list':
42 return $type_list;
43 case 'base':
44 return $type_base;
45 default:
46 return $types;
47 }
48 }
49
50 /**
51 * Implementation of hook_menu().
52 */
53 function pageroute_menu($may_cache) {
54 global $user, $_menu;
55
56 if ($may_cache) {
57 $items = array();
58 $result = db_query("SELECT * FROM {pageroute_routes}");
59
60 while ($route = db_fetch_object($result)) {
61 $route->options = unserialize($route->options);
62 $access = array_intersect(array_keys($user->roles), $route->options['access']['allowed_roles']) ? TRUE : FALSE;
63 $items[$route->prid] = array(
64 'path' => $route->path,
65 'title' => $route->path,
66 'callback' => 'pageroute_show_route',
67 'access' => $access,
68 'type' => MENU_NORMAL_ITEM,
69 );
70 if ($access) {
71 //add the route as argument
72 pageroute_update_page_index($route);
73 $items[$route->prid]['callback arguments'] = array($route);
74 }
75 }
76 return $items;
77 }
78 /*
79 * We print drupal menu tabs for pages !$may_cache so we can generate the tabs
80 * with proper pageroute path arguments appended
81 */
82 else if (!$may_cache) {
83 //Search, if we are inside a pageroute by using the cached menu items in $_menu
84 $path = $_GET['q'];
85 while ($path && !isset($_menu['callbacks'][$path])) {
86 $path = substr($path, 0, strrpos($path, '/'));
87 }
88 if ($_menu['callbacks'][$path]['callback'] == 'pageroute_show_route') {
89 //we are inside a pageroute
90 $route = $_menu['callbacks'][$path]['callback arguments'][0];
91 if ($route->options['tabs'] == PAGEROUTE_MENU_TABS) {
92 $page_name = _pageroute_init_route($route);
93 $path_arguments = _pageroute_get_path_argument($route);
94
95 foreach ($route->pages as $index => $data) {
96 if (!isset($data['no_tab']) || !$data['no_tab']) {
97 $items[] = array(
98 'path' => $route->path .'/'. $data['name'] . $path_arguments,
99 'title' => $data['title'] ? $data['title'] : $data['name'],
100 'callback' => 'pageroute_show_route',
101 'callback arguments' => array($route),
102 'access' => isset($route->page_access[$data['name']]) ? $route->page_access[$data['name']] : TRUE,
103 'type' => MENU_LOCAL_TASK,
104 'weight' => $index,
105 );
106 }
107 }
108 }
109 }
110 return $items;
111 }
112 }
113
114 /*
115 * Gets the substring, that contains all pageroute arguments to the routes path
116 */
117 function _pageroute_get_path_argument($route) {
118
119 $path_arguments = '';
120 $i = 1;
121 while (($arg = pageroute_arg($route, $i)) != NULL) {
122 $path_arguments .= '/'. $arg;
123 $i++;
124 }
125 return $path_arguments;
126 }
127
128 /*
129 * Initializes a route: take care for the arg_offset and then boot!
130 * @return $page_name
131 */
132 function _pageroute_init_route(&$route) {
133 //get the page name
134 $page_name = pageroute_arg($route, 0);
135 if (!isset($route->page_index[$page_name])) {
136 //this page name doesn't even exist, so we interprete it as argument
137 $route->options['arg_offset']--;
138 }
139 //allow modules to customize runtime page access and other stuff
140 pageroute_invoke_all('boot', $route, $page_name);
141 return $page_name;
142 }
143
144 /*
145 * Shows the given route
146 */
147 function pageroute_show_route(&$route) {
148 global $page;
149
150 //if menu tabs are used, the route has already been initialized
151 if ($route->options['tabs'] != PAGEROUTE_MENU_TABS) {
152 $page_name = _pageroute_init_route($route);
153 }
154 else {
155 $page_name = pageroute_arg($route, 0);
156 }
157 if (!pageroute_page_access($route, $page_name)) {
158 $page_name = pageroute_get_default_page_name($route);
159 if ($route->options['tabs'] == PAGEROUTE_MENU_TABS) {
160 //we have to redirect directly to the path so that the tab system can determine the active tab
161 drupal_goto($route->path. '/'. $page_name . _pageroute_get_path_argument($route), pageroute_get_new_destination($route));
162 }
163 }
164 if (isset($route->page_index[$page_name])) {
165 $page = pageroute_load_page($page_name, $route);
166
167 //add css
168 $path = drupal_get_path('module', 'pageroute') .'/pageroute.css';
169 drupal_add_css($path, 'module', 'all', FALSE);
170
171 if ($page->title) {
172 drupal_set_title(check_plain($page->title));
173 }
174 return drupal_get_form('pageroute_page_'. $page_name .'_form', $route, $page);
175 }
176 else {
177 return t('There are no pages defined for this pageroute.');
178 }
179 }
180
181 /*
182 * Implementation of hook_forms()
183 */
184 function pageroute_forms() {
185 global $page;
186
187 $forms = array();
188 //just add the ids of all pages of the active route
189 if (isset($page) && isset($page->route)) {
190 foreach(array_keys($page->route->page_index) as $page_name) {
191 $forms['pageroute_page_'. $page_name .'_form'] = array(
192 'callback' => 'pageroute_page_form',
193 );
194 }
195 }
196 return $forms;
197 }
198
199 /*
200 * Returns the form array of a page by invoking the page type's implementation
201 */
202 function pageroute_page_form($route, $page) {
203 $bases = pageroute_get_types('base');
204 $function = $bases[$page->type] .'_page_'. $page->type;
205
206 if (function_exists($function)) {
207 //for most page types the arg_offset will always be 1, so we default to one
208 $page->arg_offset = 1;
209
210 pageroute_invoke_all('show', $page);
211
212 //add tabs, buttons and other pageroute stuff
213 pageroute_decorate($form, $page);
214
215 //first submit the subforms, then the pageroute form
216 $form['#submit'] = array(
217 'subform_element_submit' => array(),
218 'pageroute_page_form_submit_prepare_target' => array(),
219 'pageroute_page_form_submit_redirect' => array(),
220 );
221 $form = $function($route, $page, $form);
222 return $form;
223 }
224 else {
225 return array(
226 'error' => array(
227 '#type' => 'markup',
228 '#value' => t('Error while generationg the page. Perhaps a module is missing.'),
229 ),
230 );
231 }
232 }
233
234 /*
235 * Prepare for the submit function. This is also a #submit callback
236 * It will determine the redirect target.
237 */
238 function pageroute_page_form_submit_prepare_target($form_id, &$form_values) {
239 $page = &$form_values['page'];
240
241 if ($form_values['page_op']) {
242 //a pageroute back/forward button has been pressed
243 $target = $form_values['page_op'] == t($page->options['back']) ? PAGEROUTE_BACK : PAGEROUTE_FORWARD;
244 }
245 else if ($page->route->options['tabs']) {
246 foreach (array_keys($page->route->page_index) as $page_name) {
247 if ($form_values['tabs_op_'. $page_name]) {
248 //a tab-like submit button has been pressed
249 $target = pageroute_create_path($page, $page_name);
250 }
251 }
252 }
253
254 if (isset($target)) {
255 $form_values['target'] = $target;
256 }
257 //let the page type customize the target
258 $return_value = pageroute_invoke($page, 'target', $form_values);
259 if (isset($return_value)) {
260 $form_values['target'] = $return_value;
261 }
262 //let other modules force another target
263 $return_value = pageroute_invoke_all('target', $page, $form_values);
264 if (isset($return_value)) {
265 $form_values['target'] = $return_value;
266 }
267 }
268
269 /*
270 * Submit function for all pageroute forms.
271 * Redirect to the set target.
272 */
273 function pageroute_page_form_submit_redirect($form_id, &$form_values) {
274 $page = &$form_values['page'];
275
276 //clear the drupal messages
277 pageroute_clear_messages($page);
278
279 //track how far the user has ever gone through the route using the states module
280 pageroute_track_user_progress($page);
281
282 //get the redirect path for the target
283 $path = pageroute_get_path_for_redirect_target($page, $form_values['target']);
284
285 if (isset($path)) {
286 if ($destination = pageroute_get_new_destination($page->route)) {
287 //handle the destination parameter
288 if ($form_values['target'] == PAGEROUTE_FORWARD && !$page->options['neighbours']['forward']) {
289 //this was the last page - redirect to the destination
290 return parse_url(urldecode(pageroute_get_new_destination($page->route, FALSE)));
291 }
292 return array($path, $destination);
293 }
294 return $path;
295 }
296 }
297
298 /*
299 * Generates a path for the given redirect target, which
300 * may be already a path or a defined target constant
301 */
302 function pageroute_get_path_for_redirect_target($page, $target) {
303 if (is_numeric($target)) {
304 switch ($target) {
305 case PAGEROUTE_BACK:
306 $back = $page->options['neighbours']['back'];
307 while ($back && !pageroute_page_access($page->route, $back)) {
308 $index = $page->route->page_index[$back];
309 $back = $page->route->pages[$index - 1]['name'];
310 }
311 if ($back) {
312 return pageroute_create_path($page, $back);
313 }
314 break;
315 case PAGEROUTE_CURRENT:
316 return pageroute_get_path($page);
317 case PAGEROUTE_FORWARD:
318 if (!$page->options['neighbours']['forward']) {
319 return pageroute_get_redirect_path($page);
320 }
321 else {
322 $forward = $page->options['neighbours']['forward'];
323 while ($forward && !pageroute_page_access($page->route, $forward)) {
324 $index = $page->route->page_index[$forward];
325 $forward = $page->route->pages[$index + 1]['name'];
326 }
327 if ($forward) {
328 return pageroute_create_path($page, $forward);
329 }
330 }
331 return pageroute_get_redirect_path($page);
332 }
333 }
334 else if ($target == PAGEROUTE_NONE) {
335 return NULL;
336 }
337 //else the target is already a ready to use path
338 return $target;
339 }
340
341 /*
342 * If set, this functions keeps the destination parameter from being applied throuugh drupal_goto.
343 * In this case it returns the destination parameter for the next page. Note that the destination
344 * parameter is saved so you can call this function more times without loosing the destination.
345 * It will never urlencode the destination
346 *
347 * @$query If the returned destination parameter should be suitable for use as query parameter
348 */
349 function pageroute_get_new_destination($route, $query = TRUE) {
350 static $destination;
351
352 if (!isset($destination) && $route->options['destination'] && isset($_REQUEST['destination'])) {
353 $destination = $_REQUEST['destination']; //don't urlencode!
354 unset($_REQUEST['destination']);
355 }
356 if (isset($destination)) {
357 return $query ? 'destination='. $destination : $destination;
358 }
359 }
360
361 /*
362 * Determines the redirect path, to which the user will be routed after the pageroute
363 */
364 function pageroute_get_redirect_path($page) {
365 if (!empty($page->route->options['redirect_path'])) {
366 return strtr($page->route->options['redirect_path'], array(
367 '!nid' => intval(pageroute_page_get_nid($page)),
368 '!uid' => intval(pageroute_page_get_uid($page)),
369 ));
370 }
371 if ($nid = pageroute_page_get_nid($page)) {
372 if (is_numeric($nid)) {
373 return 'node/'. $nid;
374 }
375 }
376 if ($uid = pageroute_page_arg($page, 1)) {
377 if (is_numeric($uid)) {
378 return 'user/'. $uid;
379 }
380 }
381 return '<front>';
382 }
383
384
385 /*
386 * Wrapper around arg()
387 * Get the next arguments after the route path with $index >= 1
388 * (Argument 0 is usually the page name)
389 */
390 function pageroute_arg(&$route, $index) {
391 if (isset($route->_new_arg[$index])) {
392 return $route->_new_arg[$index];
393 }
394 else {
395 return arg($route->options['arg_offset'] + $index);
396 }
397 }
398
399 /*
400 * Wrapper around arg()
401 * Get the next argument after all page arguments
402 * @param $index Starting with 0
403 */
404 function pageroute_page_arg($page, $index) {
405 return pageroute_arg($page->route, $page->arg_offset + $index);
406 }
407
408 /*
409 * Allows pages to add new arguments.
410 * They will be used for the generation of the next path.
411 */
412 function pageroute_add_new_arg(&$route, $arg, $index) {
413 $i = 0;
414 while ($i < $index && is_null(pageroute_arg($route, $i))) {
415 $route->_new_arg[$i] = 0;
416 $i++;
417 }
418 $route->_new_arg[$index] = $arg;
419 }
420
421 /*
422 * The second page argument is the uid, for which the page should be loaded.
423 * This function shall be used to get it
424 *
425 * @param $page The page object
426 * @param $permission An optional permission, which will be used for access checking, if the
427 * pageroute is used for not the active user. If the access check fails, the active user's uid
428 * will be returned.
429 */
430 function pageroute_page_get_uid($page, $permission = FALSE) {
431 global $user;
432 $uid = pageroute_page_arg($page, 1);
433 if (is_numeric($uid) && $uid) {
434 if ($uid != $user->uid && $permission && user_access($permission)) {
435 return $uid;
436 }
437 else if (!$permission) {
438 return $uid;
439 }
440 }
441 return $user->uid;
442 }
443
444 /*
445 * Returns the first page argument, the node id
446 */
447 function pageroute_page_get_nid($page) {
448 $arg = pageroute_page_arg($page, 0);
449 return is_numeric($arg) ? $arg : NULL;
450 }
451
452
453 /*
454 * Gets the default path of the current page
455 */
456 function pageroute_get_path(&$page) {
457 return pageroute_create_path($page, $page->name);
458 }
459
460 /*
461 * Creates a path while keeping all arguments
462 * @param $page The page object of the current page
463 * @param $next The string, e.g. page name for the next page
464 */
465 function pageroute_create_path(&$page, $next) {
466
467 $path = array($page->route->path, $next);
468
469 $arg = pageroute_page_arg($page, $index = 0);
470 while (isset($arg)) {
471 $path[] = $arg;
472 $arg = pageroute_page_arg($page, ++$index);
473 }
474 return implode('/', $path);
475 }
476
477 /*
478 * Loads the page list for a route
479 */
480 function pageroute_update_page_index(&$route) {
481 $result = db_query("SELECT * FROM {pageroute_pages} WHERE prid = %d ORDER BY weight, name", $route->prid);
482
483 $index = 0; $route->pages = array(); $route->page_index = array(); $route->page_access = array();
484 while ($page = db_fetch_object($result)) {
485 $page->options = unserialize($page->options);
486
487 if (isset($page->options['activated']) && !$page->options['activated']) {
488 //add deactivated pages to the page_index, but don't give them an index
489 //so this pages are reachable, but we won't route to them
490 $route->page_index[$page->name] = FALSE;
491 continue;
492 }
493
494 $route->pages[$index] = array('name' => $page->name, 'title' => $page->title, 'type' => $page->type);
495 if ($route->options['tabs'] && isset($page->options['no_tab']) && $page->options['no_tab']) {
496 $route->pages[$index]['no_tab'] = TRUE;
497 }
498 $route->page_index[$page->name] = $index;
499 $index++;
500 }
501 }
502
503
504 /*
505 * Invokes hook_pagerouteapi()
506 *
507 * Currently available operations:
508 * (*) boot: The route has just been invoked
509 * (*) show: This is called before a page is rendered.
510 * (*) target: The redirect target is calculated and may be forced to another value!
511 */
512 function pageroute_invoke_all($op, &$a2, $a3 = NULL) {
513 foreach (module_implements('pagerouteapi') as $module) {
514 $function = $module .'_pagerouteapi';
515 $result = $function($op, $a2, $a3);
516 if (isset($result)) {
517 $return = $result;
518 }
519 }
520 return $return;
521 }
522
523 /*
524 * Invokes a page type specific implementation, if it exists
525 * @param $page The page object or the page's type
526 * @param $op The operation that should be invoked
527 */
528 function pageroute_invoke($page, $op, $arg1 = NULL) {
529 $type = is_object($page) ? $page->type : $page;
530 $bases = pageroute_get_types('base');
531 $function = $bases[$type] .'_page_'. $type .'_'. $op;
532 if (function_exists($function)) {
533 if (is_object($page)) {
534 return $function($page->route, $page, $arg1);
535 }
536 else {
537 return $function($arg1);
538 }
539 }
540 }
541
542
543 /*
544 * Add tabs, buttons and other necessary properties to the form.
545 */
546 function pageroute_decorate(&$form, $page, $button_name = 'page_op') {
547 //initialize the redirect target with its default value
548 $types = pageroute_get_types('all');
549 $default_target = isset($types[$page->type]['default_target']) ? $types[$page->type]['default_target'] : PAGEROUTE_CURRENT;
550 $form['target'] = array('#type' => 'value', '#value' => $default_target);
551 $form['page'] = array('#type' => 'value', '#value' => $page);
552 $form['#attributes']['enctype'] = 'multipart/form-data';
553 $id = 'pageroute-page-'. $page->route->path .'-'. $page->name .'-form'; //generate a unique id
554 $form['#id'] = preg_replace('/[^A-Za-z0-9:.-]/', '-', $id);
555 pageroute_add_tabs($form, $page);
556 pageroute_add_buttons($form, $page, $button_name);
557 pageroute_get_new_destination($page->route); //make sure that the destination parameter get's removed in any case
558 }
559
560 /*
561 * Add the pageroute buttons to a given form.
562 */
563 function pageroute_add_buttons(&$form, $page, $button_name = 'page_op') {
564 //get the right options first
565 $options = pageroute_invoke($page, 'options');
566 $options = (isset($options)) ? $options : $page->options;
567
568 foreach (array('back', 'forward') as $key => $name) {
569 if (!$options[$name]) {
570 continue; //this button has been disabled
571 }
572 //apply page type specific settings if available
573 if (!isset($options['show_route_buttons'])) {
574 if (!$page->options['neighbours'][$name] && $name == 'back') {
575 continue; //there is no previous page, so don't show the button
576 }
577 }
578 else if (!$options['show_route_buttons']) {
579 continue;
580 }
581 $form['buttons'][$name]['#attributes']['class'] = 'pageroute-'. $name;
582 $form['buttons'][$name]['#type'] = 'submit';
583 $form['buttons'][$name]['#value'] = t($options[$name]);
584 $form['buttons'][$name]['#name'] = $button_name;
585 $form['buttons'][$name]['#weight'] = 10 + $key;
586 }
587 if (isset($options['cancel']) && $options['cancel']) {
588 //also add an cancel link that links to the default redirect target
589 $form['buttons']['cancel']['#process']['pageroute_process_cancel_link'] = array($options['cancel'], $form['target']['#value']);
590 }
591 if ($form['buttons']) {
592 $form['buttons']['#prefix'] = '<span class="pageroute_buttons">';
593 $form['buttons']['#suffix'] = '</span>';
594 $form['buttons']['#weight'] = 50;
595 }
596 }
597
598 /*
599 * #proccess function for the cancel link
600 * We have to do this with #process, because the page type implementation needs to have the possibility to
601 * adapt $page->arg_offset before we can get the right redirect targets
602 * Note that we also track the user progress as soon as this gets built - as the user can cancel this form
603 * he isn't forced to submit it before he can proceed
604 */
605 function pageroute_process_cancel_link($form_element, $form_values, $cancel, $target) {
606 global $page;
607
608 pageroute_track_user_progress($page);
609 $link = l(t($cancel), pageroute_get_path_for_redirect_target($page, $target), array(), pageroute_get_new_destination($page->route));
610 $form_element += array('#value' => $link, '#weight' => 9);
611 return $form_element;
612 }
613
614
615 /*
616 * Add the pageroute tabs to a given form.
617 */
618 function pageroute_add_tabs(&$form, $page) {
619
620 if ($page->route->options['tabs'] != PAGEROUTE_BUTTON_TABS || $page->route->tabs_displayed) {
621 return;
622 }
623 //mark as displayed
624 $page->route->tabs_displayed = TRUE;
625
626 foreach ($page->route->pages as $index => $data) {
627 if ((!isset($data['no_tab']) || !$data['no_tab'])) {
628 $form['tabs'][$data['name']] = array(
629 '#type' => 'submit',
630 '#value' => $data['title'] ? $data['title'] : $data['name'],
631 '#name' => 'tabs_op_'. $data['name'],
632 );
633 if (!pageroute_page_access($page->route, $data['name'])) {
634 $form['tabs'][$data['name']]['#attributes'] = array('class' => 'distant');
635 $form['tabs'][$data['name']]['#disabled'] = TRUE;
636 }
637 else if ($data['name'] == $page->name) {
638 $form['tabs'][$data['name']]['#attributes'] = array('class' => 'active');
639 }
640 }
641 }
642 $form['tabs']['#weight'] = -100;
643 $form['tabs']['#theme'] = 'pageroute_route_tabs';
644 }
645
646 /*
647 * Themes the tab-like submit buttons of a route.
648 * @param $elements The form elements of the tabs
649 */
650 function theme_pageroute_route_tabs($elements) {
651 $elements['#prefix'] = '<div class="pageroute-tabs">';
652 $elements['#suffix'] = '</div>';
653 return drupal_render($elements);
654 }
655
656 /*
657 * Gets the $page object from the database
658 * @params $page_name The page's name
659 * @params $route The page's route
660 */
661 function pageroute_load_page($page_name, $route) {
662 $page = db_fetch_object(db_query("SELECT * FROM {pageroute_pages} WHERE name = '%s' AND prid = %d", $page_name, $route->prid));
663 $page->route = &$route;
664 $page->options = unserialize($page->options);
665 return $page;
666 }
667
668 /*
669 * Exits properly by invoking hook_exit before exiting
670 */
671 function pageroute_exit_now() {
672 module_invoke_all('exit');
673 exit;
674 }
675
676 /*
677 * Implementation of hook_form_alter().
678 * Apply the settings for node edit/add forms used in a page type and add the help text
679 */
680 function pageroute_form_alter($form_id, &$form) {
681 global $page;
682
683 if (isset($form['type']) && pageroute_page_uses_content_type($page, $form['type']['#value'])
684 && ($form_id == 'node_form' || $form_id == $form['type']['#value'] .'_node_form')) {
685 //this is a node form viewed during a pageroute
686
687 //add help text, because node.module only shows that for node/add/* forms
688 $type = node_get_types('type', $page->options['content-type']);
689 if ($type->help) {
690 $form['help'] = array(
691 '#prefix' => '<div class="help">', // the same as in theme_help()
692 '#value' => '<p>'. filter_xss_admin($type->help) .'</p>',
693 '#suffix' => '</div>',
694 '#weight' => -90,
695 );
696 }
697
698 //get the options and apply them to the form
699 $options = pageroute_invoke($page, 'options');
700 $options = (isset($options)) ? $options : $page->options;
701
702 foreach (array('preview', 'submit') as $name) {
703 if (!$options[$name]) {
704 unset($form[$name]);
705 }
706 }
707 if ($options['nodelete'] && $form['delete']) {
708 unset($form['delete']);
709 }
710 }
711 }
712
713 /*
714 * Returns if the page makes use of the given content type
715 */
716 function pageroute_page_uses_content_type($page, $content_type) {
717 return $content_type == $page->options['content-type'] || (is_array($page->options['content-type']) && in_array($content_type, $page->options['content-type']));
718 }
719
720 /*
721 * Clears the drupal messages, if configured and the current page doesn't prevent it
722 */
723 function pageroute_clear_messages($page) {
724 if ($page->route->options['no_messages']) {
725 $options = pageroute_invoke($page, 'options');
726 $options = (isset($options)) ? $options : $page->options;
727 if (!isset($options['show_messages']) || !$options['show_messages']) {
728 unset($_SESSION['messages']['status']);
729 }
730 }
731 }
732
733 /*
734 * Tracks how far the user has ever gone through the route using the states module
735 * We'll track only uncompleted pageroutes,
736 * so if the user has completed a route we unset the state machine value
737 */
738 function pageroute_track_user_progress(&$page) {
739 global $user;
740
741 if ($page->route->options['track_user'] && module_exists('states')) {
742 //get the right user object
743 $uid = pageroute_page_get_uid($page);
744 $account = ($user->uid != $uid && user_access('administer nodes') && is_numeric($uid)) ? user_load(array('uid' => $uid)) : $user;
745 $state = states_entity_get_machine_state($account, 'pageroute_'. $page->route->prid);
746 $page_index = $page->route->page_index;
747 //also check the page_name, so that only activated pages are set
748 if (isset($state) && $page_index[$page->name] !== FALSE && (!isset($page_index[$state]) || $page_index[$state] < $page_index[$page->name])) {
749 //pageroute completed ?
750 $state = $page->options['neighbours']['forward'] ? $page->name : NULL;
751 states_machine_set_state($account, 'pageroute_'. $page->route->prid, $state);
752 //also update the page access immediately, so that pageroute can route accordingly
753 pageroute_set_page_access_by_state($page->route, $state);
754 }
755 }
756 }
757
758 /*
759 * Implementation of hook_states()
760 */
761 function pageroute_states() {
762 $machines = array();
763 $result = db_query("SELECT * FROM {pageroute_routes}");
764 while ($route = db_fetch_object($result)) {
765 $route->options = unserialize($route->options);
766
767 if ($route->options['track_user']) {
768 pageroute_update_page_index($route);
769 $pages = array_keys($route->page_index);
770 array_pop($pages); //remove the last page
771
772 $machines['pageroute_'. $route->prid] = array(
773 '#label' => 'Uncompleted pageroute: '. $route->path,
774 '#entity' => 'user',
775 '#roles' => array_filter($route->options['access']['allowed_roles']),
776 '#states' => array_merge(array('Not started'), $pages),
777 '#init_state' => 'Not started',
778 '#path' => $route->path,
779 );
780 }
781 }
782 return $machines;
783 }
784
785 /*
786 * Checks if this is a valid page and if access to the page shall be granted
787 */
788 function pageroute_page_access($route, $page_name) {
789 if (!isset($route->page_index[$page_name])) {
790 return FALSE;
791 }
792 if (isset($route->page_access[$page_name]) && $route->page_access[$page_name] === FALSE) {
793 return FALSE;
794 }
795 return TRUE;
796 }
797
798 /*
799 * Returns the default page's name for this route and user
800 * Usually this is the first page, except for the case that user tracking
801 * with the states module is activated and the user has already gone through
802 * some pages
803 */
804 function pageroute_get_default_page_name($route) {
805 $index = 0; //this means load the first page
806
807 if ($route->options['track_user'] && module_exists('states')) {
808 if ($state = pageroute_get_user_state($route)) {
809 if (isset($route->page_index[$state])) {
810 $index = $route->page_index[$state] + 1;
811 }
812 }
813 if (module_exists('pageroute_nodefamily') && $state = pageroute_nodefamily_get_state($route)) {
814 if (isset($route->page_index[$state])) {
815 $index = $route->page_index[$state] + 1;
816 }
817 }
818 }
819 //get the page name
820 if (isset($route->pages[$index]) && $route->page_access[$route->pages[$index]['name']] !== FALSE) {
821 return $route->pages[$index]['name'];
822 }
823 else {
824 return $route->pages[0]['name'];
825 }
826 }
827
828 /*
829 * Gets the state of the user for which we go through the current active route
830 */
831 function pageroute_get_user_state($route, $page = NULL) {
832 global $user;
833 //get the right user object
834 $uid = isset($page) ? pageroute_page_get_uid($page) : pageroute_arg($route, 2);
835 $account = ($user->uid != $uid && user_access('administer nodes') && is_numeric($uid)) ? user_load(array('uid' => $uid)) : $user;
836 return states_entity_get_machine_state($account, 'pageroute_'. $route->prid);
837 }
838
839 /*
840 * Implementation of hook_pagerouteapi()
841 * If user progress verification with the help of the states module is turned on,
842 * we deny access to all pages after the next page
843 */
844 function pageroute_pagerouteapi($op, &$route, $page_name) {
845 if ($op == 'boot' && module_exists('states') && $route->options['track_user']) {
846 if ($state = pageroute_get_user_state($route)) {
847 pageroute_set_page_access_by_state($route, $state);
848 }
849 }
850 }
851
852 /*
853 * Denies access to all pages after the next page
854 */
855 function pageroute_set_page_access_by_state(&$route, $state) {
856 $page_index = $route->page_index;
857 $valid_index = isset($page_index[$state]) ? $page_index[$state] + 1 : 0;
858
859 $route->page_access = array();
860 foreach ($page_index as $name => $index) {
861 if ($index > $valid_index) {
862 $route->page_access[$name] = FALSE;
863 }
864 }
865 }

  ViewVC Help
Powered by ViewVC 1.1.2