Projet

Général

Profil

Paste
Télécharger (17,6 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ctools / includes / context-task-handler.inc @ 7e72b748

1
<?php
2

    
3
/**
4
 * @file
5
 * Support for creating 'context' type task handlers.
6
 *
7
 * Context task handlers expect the task to provide 0 or more contexts. The
8
 * task handler should use those contexts as selection rules, as well as
9
 * rendering with them.
10
 *
11
 * The functions and forms in this file should be common to every context type
12
 * task handler made.
13
 *
14
 * Forms:
15
 * - ...
16
 */
17

    
18
/**
19
 * Render a context type task handler given a list of handlers
20
 * attached to a type.
21
 *
22
 * @param $task
23
 *   The $task object in use.
24
 * @param $subtask
25
 *   The id of the subtask in use.
26
 * @param $contexts
27
 *   The context objects in use.
28
 * @param $args
29
 *   The raw arguments behind the contexts.
30
 * @param $page
31
 *   If TRUE then this renderer owns the page and can use theme('page')
32
 *   for no blocks; if false, output is returned regardless of any no
33
 *   blocks settings.
34
 *
35
 * @return
36
 *   Either the output or NULL if there was output, FALSE if no handler
37
 *   accepted the task. If $page is FALSE then the $info block is returned instead.
38
 */
39
function ctools_context_handler_render($task, $subtask, $contexts, $args) {
40
  // Load the landlers, choosing only enabled handlers.
41
  $handlers = page_manager_load_sorted_handlers($task, $subtask ? $subtask['name'] : '', TRUE);
42

    
43
  $id = ctools_context_handler_get_render_handler($task, $subtask, $handlers, $contexts, $args);
44
  if ($id) {
45
    return ctools_context_handler_render_handler($task, $subtask, $handlers[$id], $contexts, $args);
46
  }
47

    
48
  return FALSE;
49
}
50

    
51
/**
52
 * Figure out which of the listed handlers should be used to render.
53
 */
54
function ctools_context_handler_get_render_handler($task, $subtask, $handlers, $contexts, $args) {
55
  // Try each handler.
56
  foreach ($handlers as $id => $handler) {
57
    $plugin = page_manager_get_task_handler($handler->handler);
58
    // First, see if the handler has a tester.
59
    $function = ctools_plugin_get_function($plugin, 'test');
60
    if ($function) {
61
      $test = $function($handler, $contexts, $args);
62
      if ($test) {
63
        return $id;
64
      }
65
    }
66
    else {
67
      // If not, if it's a 'context' type handler, use the default tester.
68
      if ($plugin['handler type'] == 'context') {
69
        $test = ctools_context_handler_default_test($handler, $contexts, $args);
70
        if ($test) {
71
          return $id;
72
        }
73
      }
74
    }
75
  }
76

    
77
  return FALSE;
78
}
79

    
80
/**
81
 * Default test function to see if a task handler should be rendered.
82
 *
83
 * This tests against the standard selection criteria that most task
84
 * handlers should be implementing.
85
 */
86
function ctools_context_handler_default_test($handler, $base_contexts, $args) {
87
  ctools_include('context');
88
  // Add my contexts.
89
  $contexts = ctools_context_handler_get_handler_contexts($base_contexts, $handler);
90

    
91
  // Test.
92
  return ctools_context_handler_select($handler, $contexts);
93
}
94

    
95
/**
96
 * Render a task handler.
97
 */
98
function ctools_context_handler_render_handler($task, $subtask, $handler, $contexts, $args, $page = TRUE) {
99
  $function = page_manager_get_renderer($handler);
100
  if (!$function) {
101
    return NULL;
102
  }
103

    
104
  if ($page) {
105
    if ($subtask) {
106
      $task_name = page_manager_make_task_name($task['name'], $subtask['name']);
107
    }
108
    else {
109
      $task_name = $task['name'];
110
    }
111

    
112
    page_manager_get_current_page(array(
113
      'name' => $task_name,
114
      'task' => $task,
115
      'subtask' => $subtask,
116
      'contexts' => $contexts,
117
      'arguments' => $args,
118
      'handler' => $handler,
119
    ));
120
  }
121

    
122
  $info = $function($handler, $contexts, $args);
123
  if (!$info) {
124
    return NULL;
125
  }
126

    
127
  $context = array(
128
    'args' => $args,
129
    'contexts' => $contexts,
130
    'task' => $task,
131
    'subtask' => $subtask,
132
    'handler' => $handler,
133
  );
134
  drupal_alter('ctools_render', $info, $page, $context);
135

    
136
  // If we don't own the page, let the caller deal with rendering.
137
  if (!$page) {
138
    return $info;
139
  }
140

    
141
  if (!empty($info['response code']) && $info['response code'] != 200) {
142
    switch ($info['response code']) {
143
      case 403:
144
        return MENU_ACCESS_DENIED;
145

    
146
      case 404:
147
        return MENU_NOT_FOUND;
148

    
149
      case 410:
150
        drupal_add_http_header('Status', '410 Gone');
151
        drupal_exit();
152
        break;
153

    
154
      case 301:
155
      case 302:
156
      case 303:
157
      case 304:
158
      case 305:
159
      case 307:
160
        $info += array(
161
          'query' => array(),
162
          'fragment' => '',
163
        );
164
        $options = array(
165
          'query' => $info['query'],
166
          'fragment' => $info['fragment'],
167
        );
168
        drupal_goto($info['destination'], $options, $info['response code']);
169
        // @todo -- should other response codes be supported here?
170
    }
171
  }
172

    
173
  $plugin = page_manager_get_task_handler($handler->handler);
174

    
175
  if (module_exists('contextual') && user_access('access contextual links') && isset($handler->task)) {
176
    // Provide a contextual link to edit this, if we can:
177
    $callback = isset($plugin['contextual link']) ? $plugin['contextual link'] : 'ctools_task_handler_default_contextual_link';
178
    if ($callback && function_exists($callback)) {
179
      $links = $callback($handler, $plugin, $contexts, $args);
180
    }
181

    
182
    if (!empty($links) && is_array($links)) {
183
      $build = array(
184
        '#theme_wrappers' => array('container'),
185
        '#attributes' => array('class' => array('contextual-links-region')),
186
      );
187

    
188
      if (!is_array($info['content'])) {
189
        $build['content']['#markup'] = $info['content'];
190
      }
191
      else {
192
        $build['content'] = $info['content'];
193
      }
194

    
195
      $build['contextual_links'] = array(
196
        '#prefix' => '<div class="contextual-links-wrapper">',
197
        '#suffix' => '</div>',
198
        '#theme' => 'links__contextual',
199
        '#links' => $links,
200
        '#attributes' => array('class' => array('contextual-links')),
201
        '#attached' => array(
202
          'library' => array(array('contextual', 'contextual-links')),
203
        ),
204
      );
205
      $info['content'] = $build;
206
    }
207
  }
208

    
209
  foreach (ctools_context_handler_get_task_arguments($task, $subtask) as $id => $argument) {
210
    $plugin = ctools_get_argument($argument['name']);
211
    $cid = ctools_context_id($argument, 'argument');
212
    if (!empty($contexts[$cid]) && ($function = ctools_plugin_get_function($plugin, 'breadcrumb'))) {
213
      $function($argument['settings'], $contexts[$cid]);
214
    }
215
  }
216

    
217
  if (isset($info['title'])) {
218
    drupal_set_title($info['title'], PASS_THROUGH);
219
  }
220

    
221
  // Only directly output if $page was set to true.
222
  if (!empty($info['no_blocks'])) {
223
    ctools_set_no_blocks(FALSE);
224
  }
225
  return $info['content'];
226
}
227

    
228
/**
229
 * Default function to provide contextual link for a task as defined by the handler.
230
 *
231
 * This provides a simple link to th main content operation and is suitable
232
 * for most normal handlers. Setting 'contextual link' to a function overrides
233
 * this and setting it to FALSE will prevent a contextual link from appearing.
234
 */
235
function ctools_task_handler_default_contextual_link($handler, $plugin, $contexts, $args) {
236
  if (!user_access('administer page manager')) {
237
    return;
238
  }
239

    
240
  $task = page_manager_get_task($handler->task);
241

    
242
  $title = !empty($task['tab title']) ? $task['tab title'] : t('Edit @type', array('@type' => $plugin['title']));
243
  $trail = array();
244
  if (!empty($plugin['tab operation'])) {
245
    if (is_array($plugin['tab operation'])) {
246
      $trail = $plugin['tab operation'];
247
    }
248
    elseif (function_exists($plugin['tab operation'])) {
249
      $trail = $plugin['tab operation']($handler, $contexts, $args);
250
    }
251
  }
252
  $path = page_manager_edit_url(page_manager_make_task_name($handler->task, $handler->subtask), $trail);
253

    
254
  $links = array(array(
255
    'href' => $path,
256
    'title' => $title,
257
    'query' => drupal_get_destination(),
258
  ),
259
  );
260

    
261
  return $links;
262
}
263

    
264
/**
265
 * Called to execute actions that should happen before a handler is rendered.
266
 */
267
function ctools_context_handler_pre_render($handler, $contexts, $args) {
268
  foreach (module_implements('ctools_context_handler_pre_render') as $module) {
269
    $function = $module . '_ctools_context_handler_pre_render';
270
    $function($handler, $contexts, $args);
271
  }
272
}
273

    
274
/**
275
 * Compare arguments to contexts for selection purposes.
276
 *
277
 * @param $handler
278
 *   The handler in question.
279
 * @param $contexts
280
 *   The context objects provided by the task.
281
 *
282
 * @return
283
 *   TRUE if these contexts match the selection rules. NULL or FALSE
284
 *   otherwise.
285
 */
286
function ctools_context_handler_select($handler, $contexts) {
287
  if (empty($handler->conf['access'])) {
288
    return TRUE;
289
  }
290

    
291
  ctools_include('context');
292
  return ctools_access($handler->conf['access'], $contexts);
293
}
294

    
295
/**
296
 * Get the array of summary strings for the arguments.
297
 *
298
 * These summary strings are used to communicate to the user what
299
 * arguments the task handlers are selecting.
300
 *
301
 * @param $task
302
 *   The loaded task plugin.
303
 * @param $subtask
304
 *   The subtask id.
305
 * @param $handler
306
 *   The handler to be checked.
307
 */
308
function ctools_context_handler_summary($task, $subtask, $handler) {
309
  if (empty($handler->conf['access']['plugins'])) {
310
    return array();
311
  }
312

    
313
  ctools_include('context');
314
  $strings = array();
315
  $contexts = ctools_context_handler_get_all_contexts($task, $subtask, $handler);
316

    
317
  foreach ($handler->conf['access']['plugins'] as $test) {
318
    $plugin = ctools_get_access_plugin($test['name']);
319
    if ($string = ctools_access_summary($plugin, $contexts, $test)) {
320
      $strings[] = $string;
321
    }
322
  }
323

    
324
  return $strings;
325
}
326

    
327
// --------------------------------------------------------------------------
328
// Tasks and Task handlers can both have their own sources of contexts.
329
// Sometimes we need all of these contexts at once (when editing
330
// the task handler, for example) but sometimes we need them separately
331
// (when a task has contexts loaded and is trying out the task handlers,
332
// for example). Therefore there are two paths we can take to getting contexts.
333
/**
334
 * Load the contexts for a task, using arguments.
335
 *
336
 * This creates the base array of contexts, loaded from arguments, suitable
337
 * for use in rendering.
338
 */
339
function ctools_context_handler_get_task_contexts($task, $subtask, $args) {
340
  $contexts = ctools_context_handler_get_base_contexts($task, $subtask);
341
  $arguments = ctools_context_handler_get_task_arguments($task, $subtask);
342
  ctools_context_get_context_from_arguments($arguments, $contexts, $args);
343

    
344
  return $contexts;
345
}
346

    
347
/**
348
 * Load the contexts for a task handler.
349
 *
350
 * This expands a base set of contexts passed in from a task with the
351
 * contexts defined on the task handler. The contexts from the task
352
 * must already have been loaded.
353
 */
354
function ctools_context_handler_get_handler_contexts($contexts, $handler) {
355
  $object = ctools_context_handler_get_handler_object($handler);
356
  return ctools_context_load_contexts($object, FALSE, $contexts);
357
}
358

    
359
/**
360
 * Load the contexts for a task and task handler together.
361
 *
362
 * This pulls the arguments from a task and everything else from a task
363
 * handler and loads them as a group. Since there is no data, this loads
364
 * the contexts as placeholders.
365
 */
366
function ctools_context_handler_get_all_contexts($task, $subtask, $handler) {
367
  $contexts = array();
368

    
369
  $object = ctools_context_handler_get_task_object($task, $subtask, $handler);
370
  $contexts = ctools_context_load_contexts($object, TRUE, $contexts);
371
  ctools_context_handler_set_access_restrictions($task, $subtask, $handler, $contexts);
372
  return $contexts;
373
}
374

    
375
/**
376
 * Create an object suitable for use with the context system that kind of
377
 * expects things in a certain, kind of clunky format.
378
 */
379
function ctools_context_handler_get_handler_object($handler) {
380
  $object = new stdClass();
381
  $object->name = $handler->name;
382
  $object->contexts = isset($handler->conf['contexts']) ? $handler->conf['contexts'] : array();
383
  $object->relationships = isset($handler->conf['relationships']) ? $handler->conf['relationships'] : array();
384

    
385
  return $object;
386
}
387

    
388
/**
389
 * Create an object suitable for use with the context system that kind of
390
 * expects things in a certain, kind of clunky format. This one adds in
391
 * arguments from the task.
392
 */
393
function ctools_context_handler_get_task_object($task, $subtask, $handler) {
394
  $object = new stdClass();
395
  $object->name = !empty($handler->name) ? $handler->name : 'temp';
396
  $object->base_contexts = ctools_context_handler_get_base_contexts($task, $subtask, TRUE);
397
  $object->arguments = ctools_context_handler_get_task_arguments($task, $subtask);
398
  $object->contexts = isset($handler->conf['contexts']) ? $handler->conf['contexts'] : array();
399
  $object->relationships = isset($handler->conf['relationships']) ? $handler->conf['relationships'] : array();
400

    
401
  return $object;
402
}
403

    
404
/**
405
 * Get base contexts from a task, if it has any.
406
 *
407
 * Tasks can get their contexts either from base contexts or arguments; base
408
 * contexts extract their information from the environment.
409
 */
410
function ctools_context_handler_get_base_contexts($task, $subtask, $placeholders = FALSE) {
411
  if ($function = ctools_plugin_get_function($task, 'get base contexts')) {
412
    return $function($task, $subtask, $placeholders);
413
  }
414

    
415
  return array();
416
}
417

    
418
/**
419
 * Get the arguments from a task that are used to load contexts.
420
 */
421
function ctools_context_handler_get_task_arguments($task, $subtask) {
422
  if ($function = ctools_plugin_get_function($task, 'get arguments')) {
423
    return $function($task, $subtask);
424
  }
425

    
426
  return array();
427
}
428

    
429
/**
430
 * Set any access restrictions on the contexts for a handler.
431
 *
432
 * Both the task and the handler could add restrictions to the contexts
433
 * based upon the access control. These restrictions might be useful
434
 * to limit what kind of content appears in the add content dialog;
435
 * for example, if we have an access item that limits a node context
436
 * to only 'story' and 'page' types, there is no need for content that
437
 * only applies to the 'poll' type to appear.
438
 */
439
function ctools_context_handler_set_access_restrictions($task, $subtask, $handler, &$contexts) {
440
  // First, for the task:
441
  if ($function = ctools_plugin_get_function($task, 'access restrictions')) {
442
    $function($task, $subtask, $contexts);
443
  }
444

    
445
  // Then for the handler:
446
  if (isset($handler->conf['access'])) {
447
    ctools_access_add_restrictions($handler->conf['access'], $contexts);
448
  }
449
}
450

    
451
/**
452
 * Form to choose context based selection rules for a task handler.
453
 *
454
 * The configuration will be assumed to go simply in $handler->conf and
455
 * will be keyed by the argument ID.
456
 */
457
function ctools_context_handler_edit_criteria($form, &$form_state) {
458
  if (!isset($form_state['handler']->conf['access'])) {
459
    $form_state['handler']->conf['access'] = array();
460
  }
461

    
462
  ctools_include('context');
463
  ctools_include('modal');
464
  ctools_include('ajax');
465
  ctools_modal_add_plugin_js(ctools_get_access_plugins());
466
  ctools_include('context-access-admin');
467
  $form_state['module'] = (isset($form_state['module'])) ? $form_state['module'] : 'page_manager_task_handler';
468
  // Encode a bunch of info into the argument so we can get our cache later.
469
  $form_state['callback argument'] = $form_state['task_name'] . '*' . $form_state['handler']->name;
470
  $form_state['access'] = $form_state['handler']->conf['access'];
471
  $form_state['no buttons'] = TRUE;
472
  $form_state['contexts'] = ctools_context_handler_get_all_contexts($form_state['task'], $form_state['subtask'], $form_state['handler']);
473

    
474
  $form['markup'] = array(
475
    '#markup' => '<div class="description">' .
476
    t('If there is more than one variant on a page, when the page is visited each variant is given an opportunity to be displayed. Starting from the first variant and working to the last, each one tests to see if its selection rules will pass. The first variant that meets its criteria (as specified below) will be used.') .
477
    '</div>',
478
  );
479
  $form = ctools_access_admin_form($form, $form_state);
480
  return $form;
481
}
482

    
483
/**
484
 * Submit handler for rules selection.
485
 */
486
function ctools_context_handler_edit_criteria_submit(&$form, &$form_state) {
487
  $form_state['handler']->conf['access']['logic'] = $form_state['values']['logic'];
488
}
489

    
490
/**
491
 * Edit contexts that go with this panel.
492
 */
493
function ctools_context_handler_edit_context($form, &$form_state) {
494
  ctools_include('context-admin');
495
  ctools_context_admin_includes();
496

    
497
  $handler = $form_state['handler'];
498
  $page = $form_state['page'];
499
  $cache_name = $handler->name ? $handler->name : 'temp';
500
  if (isset($page->context_cache[$cache_name])) {
501
    $cache = $page->context_cache[$cache_name];
502
  }
503
  else {
504
    $cache = ctools_context_handler_get_task_object($form_state['task'], $form_state['subtask'], $form_state['handler']);
505
    $form_state['page']->context_cache[$cache_name] = $cache;
506
  }
507

    
508
  $form['right'] = array(
509
    '#prefix' => '<div class="clearfix"><div class="right-container">',
510
    '#suffix' => '</div>',
511
  );
512

    
513
  $form['left'] = array(
514
    '#prefix' => '<div class="left-container">',
515
    '#suffix' => '</div></div>',
516
  );
517

    
518
  $module = 'page_manager_context::' . $page->task_name;
519
  ctools_context_add_context_form($module, $form, $form_state, $form['right']['contexts_table'], $cache);
520
  ctools_context_add_relationship_form($module, $form, $form_state, $form['right']['relationships_table'], $cache);
521

    
522
  $theme_vars = array();
523
  $theme_vars['object'] = $cache;
524
  $theme_vars['header'] = t('Summary of contexts');
525
  $form['left']['summary'] = array(
526
    '#prefix' => '<div class="page-manager-contexts">',
527
    '#suffix' => '</div>',
528
    '#markup' => theme('ctools_context_list', $theme_vars),
529
  );
530

    
531
  $form_state['context_object'] = &$cache;
532
  return $form;
533
}
534

    
535
/**
536
 * Process submission of the context edit form.
537
 */
538
function ctools_context_handler_edit_context_submit(&$form, &$form_state) {
539
  $handler = &$form_state['handler'];
540

    
541
  $cache_name = $handler->name ? $handler->name : 'temp';
542

    
543
  $handler->conf['contexts'] = $form_state['context_object']->contexts;
544
  $handler->conf['relationships'] = $form_state['context_object']->relationships;
545
  if (isset($form_state['page']->context_cache[$cache_name])) {
546
    unset($form_state['page']->context_cache[$cache_name]);
547
  }
548
}