Projet

Général

Profil

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

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

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
 * @return
35
 *   Either the output or NULL if there was output, FALSE if no handler
36
 *   accepted the task. If $page is FALSE then the $info block is returned instead.
37
 */
38
function ctools_context_handler_render($task, $subtask, $contexts, $args) {
39
  // Load the landlers, choosing only enabled handlers.
40
  $handlers = page_manager_load_sorted_handlers($task, $subtask ? $subtask['name'] : '', TRUE);
41

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

    
47
  return FALSE;
48
}
49

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

    
76
  return FALSE;
77
}
78

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

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

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

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

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

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

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

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

    
140
  if (!empty($info['response code']) && $info['response code'] != 200) {
141
    switch ($info['response code']) {
142
      case 403:
143
        return MENU_ACCESS_DENIED;
144
      case 404:
145
        return MENU_NOT_FOUND;
146
      case 410:
147
        drupal_add_http_header('Status', '410 Gone');
148
        drupal_exit();
149
        break;
150
      case 301:
151
      case 302:
152
      case 303:
153
      case 304:
154
      case 305:
155
      case 307:
156
        $info += array(
157
          'query' => array(),
158
          'fragment' => '',
159
        );
160
        $options = array(
161
          'query' => $info['query'],
162
          'fragment' => $info['fragment'],
163
        );
164
        drupal_goto($info['destination'], $options, $info['response code']);
165
      // @todo -- should other response codes be supported here?
166
    }
167
  }
168

    
169
  $plugin = page_manager_get_task_handler($handler->handler);
170

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

    
178
    if (!empty($links) && is_array($links)) {
179
      $build = array(
180
        '#theme_wrappers' => array('container'),
181
        '#attributes' => array('class' => array('contextual-links-region')),
182
      );
183

    
184
      if (!is_array($info['content'])) {
185
        $build['content']['#markup'] = $info['content'];
186
      }
187
      else {
188
        $build['content'] = $info['content'];
189
      }
190

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

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

    
213
  if (isset($info['title'])) {
214
    drupal_set_title($info['title'], PASS_THROUGH);
215
  }
216

    
217
  // Only directly output if $page was set to true.
218
  if (!empty($info['no_blocks'])) {
219
    ctools_set_no_blocks(FALSE);
220
  }
221
  return $info['content'];
222
}
223

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

    
236
  $task = page_manager_get_task($handler->task);
237

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

    
250
  $links = array(array(
251
    'href' => $path,
252
    'title' => $title,
253
    'query' => drupal_get_destination(),
254
  ));
255

    
256
  return $links;
257
}
258

    
259
/**
260
 * Called to execute actions that should happen before a handler is rendered.
261
 */
262
function ctools_context_handler_pre_render($handler, $contexts, $args) { }
263

    
264
/**
265
 * Compare arguments to contexts for selection purposes.
266
 *
267
 * @param $handler
268
 *   The handler in question.
269
 * @param $contexts
270
 *   The context objects provided by the task.
271
 *
272
 * @return
273
 *   TRUE if these contexts match the selection rules. NULL or FALSE
274
 *   otherwise.
275
 */
276
function ctools_context_handler_select($handler, $contexts) {
277
  if (empty($handler->conf['access'])) {
278
    return TRUE;
279
  }
280

    
281
  ctools_include('context');
282
  return ctools_access($handler->conf['access'], $contexts);
283
}
284

    
285
/**
286
 * Get the array of summary strings for the arguments.
287
 *
288
 * These summary strings are used to communicate to the user what
289
 * arguments the task handlers are selecting.
290
 *
291
 * @param $task
292
 *   The loaded task plugin.
293
 * @param $subtask
294
 *   The subtask id.
295
 * @param $handler
296
 *   The handler to be checked.
297
 */
298
function ctools_context_handler_summary($task, $subtask, $handler) {
299
  if (empty($handler->conf['access']['plugins'])) {
300
    return array();
301
  }
302

    
303
  ctools_include('context');
304
  $strings = array();
305
  $contexts = ctools_context_handler_get_all_contexts($task, $subtask, $handler);
306

    
307
  foreach ($handler->conf['access']['plugins'] as $test) {
308
    $plugin = ctools_get_access_plugin($test['name']);
309
    if ($string = ctools_access_summary($plugin, $contexts, $test)) {
310
      $strings[] = $string;
311
    }
312
  }
313

    
314
  return $strings;
315
}
316

    
317
// --------------------------------------------------------------------------
318
// Tasks and Task handlers can both have their own sources of contexts.
319
// Sometimes we need all of these contexts at once (when editing
320
// the task handler, for example) but sometimes we need them separately
321
// (when a task has contexts loaded and is trying out the task handlers,
322
// for example). Therefore there are two paths we can take to getting contexts.
323

    
324
/**
325
 * Load the contexts for a task, using arguments.
326
 *
327
 * This creates the base array of contexts, loaded from arguments, suitable
328
 * for use in rendering.
329
 */
330
function ctools_context_handler_get_task_contexts($task, $subtask, $args) {
331
  $contexts = ctools_context_handler_get_base_contexts($task, $subtask);
332
  $arguments = ctools_context_handler_get_task_arguments($task, $subtask);
333
  ctools_context_get_context_from_arguments($arguments, $contexts, $args);
334

    
335
  return $contexts;
336
}
337

    
338
/**
339
 * Load the contexts for a task handler.
340
 *
341
 * This expands a base set of contexts passed in from a task with the
342
 * contexts defined on the task handler. The contexts from the task
343
 * must already have been loaded.
344
 */
345
function ctools_context_handler_get_handler_contexts($contexts, $handler) {
346
  $object = ctools_context_handler_get_handler_object($handler);
347
  return ctools_context_load_contexts($object, FALSE, $contexts);
348
}
349

    
350
/**
351
 * Load the contexts for a task and task handler together.
352
 *
353
 * This pulls the arguments from a task and everything else from a task
354
 * handler and loads them as a group. Since there is no data, this loads
355
 * the contexts as placeholders.
356
 */
357
function ctools_context_handler_get_all_contexts($task, $subtask, $handler) {
358
  $contexts = array();
359

    
360
  $object = ctools_context_handler_get_task_object($task, $subtask, $handler);
361
  $contexts = ctools_context_load_contexts($object, TRUE, $contexts);
362
  ctools_context_handler_set_access_restrictions($task, $subtask, $handler, $contexts);
363
  return $contexts;
364
}
365

    
366
/**
367
 * Create an object suitable for use with the context system that kind of
368
 * expects things in a certain, kind of clunky format.
369
 */
370
function ctools_context_handler_get_handler_object($handler) {
371
  $object = new stdClass;
372
  $object->name = $handler->name;
373
  $object->contexts = isset($handler->conf['contexts']) ? $handler->conf['contexts'] : array();
374
  $object->relationships = isset($handler->conf['relationships']) ? $handler->conf['relationships'] : array();
375

    
376
  return $object;
377
}
378

    
379
/**
380
 * Create an object suitable for use with the context system that kind of
381
 * expects things in a certain, kind of clunky format. This one adds in
382
 * arguments from the task.
383
 */
384
function ctools_context_handler_get_task_object($task, $subtask, $handler) {
385
  $object = new stdClass;
386
  $object->name = !empty($handler->name) ? $handler->name : 'temp';
387
  $object->base_contexts = ctools_context_handler_get_base_contexts($task, $subtask, TRUE);
388
  $object->arguments = ctools_context_handler_get_task_arguments($task, $subtask);
389
  $object->contexts = isset($handler->conf['contexts']) ? $handler->conf['contexts'] : array();
390
  $object->relationships = isset($handler->conf['relationships']) ? $handler->conf['relationships'] : array();
391

    
392
  return $object;
393
}
394

    
395
/**
396
 * Get base contexts from a task, if it has any.
397
 *
398
 * Tasks can get their contexts either from base contexts or arguments; base
399
 * contexts extract their information from the environment.
400
 */
401
function ctools_context_handler_get_base_contexts($task, $subtask, $placeholders = FALSE) {
402
  if ($function = ctools_plugin_get_function($task, 'get base contexts')) {
403
    return $function($task, $subtask, $placeholders);
404
  }
405

    
406
  return array();
407
}
408

    
409
/**
410
 * Get the arguments from a task that are used to load contexts.
411
 */
412
function ctools_context_handler_get_task_arguments($task, $subtask) {
413
  if ($function = ctools_plugin_get_function($task, 'get arguments')) {
414
    return $function($task, $subtask);
415
  }
416

    
417
  return array();
418
}
419

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

    
436
  // Then for the handler:
437
  if (isset($handler->conf['access'])) {
438
    ctools_access_add_restrictions($handler->conf['access'], $contexts);
439
  }
440
}
441

    
442
/**
443
 * Form to choose context based selection rules for a task handler.
444
 *
445
 * The configuration will be assumed to go simply in $handler->conf and
446
 * will be keyed by the argument ID.
447
 */
448
function ctools_context_handler_edit_criteria($form, &$form_state) {
449
  if (!isset($form_state['handler']->conf['access'])) {
450
    $form_state['handler']->conf['access'] = array();
451
  }
452

    
453
  ctools_include('context');
454
  ctools_include('modal');
455
  ctools_include('ajax');
456
  ctools_modal_add_plugin_js(ctools_get_access_plugins());
457
  ctools_include('context-access-admin');
458
  $form_state['module'] = (isset($form_state['module'])) ? $form_state['module'] : 'page_manager_task_handler';
459
  // Encode a bunch of info into the argument so we can get our cache later
460
  $form_state['callback argument'] = $form_state['task_name'] . '*' . $form_state['handler']->name;
461
  $form_state['access'] = $form_state['handler']->conf['access'];
462
  $form_state['no buttons'] = TRUE;
463
  $form_state['contexts'] = ctools_context_handler_get_all_contexts($form_state['task'], $form_state['subtask'], $form_state['handler']);
464

    
465
  $form['markup'] = array(
466
    '#markup' => '<div class="description">' .
467
    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.') .
468
    '</div>',
469
  );
470
  $form = ctools_access_admin_form($form, $form_state);
471
  return $form;
472
}
473

    
474
/**
475
 * Submit handler for rules selection
476
 */
477
function ctools_context_handler_edit_criteria_submit(&$form, &$form_state) {
478
  $form_state['handler']->conf['access']['logic'] = $form_state['values']['logic'];
479
}
480

    
481
/**
482
 * Edit contexts that go with this panel.
483
 */
484
function ctools_context_handler_edit_context($form, &$form_state) {
485
  ctools_include('context-admin');
486
  ctools_context_admin_includes();
487

    
488
  $handler = $form_state['handler'];
489
  $page = $form_state['page'];
490
  $cache_name = $handler->name ? $handler->name : 'temp';
491
  if (isset($page->context_cache[$cache_name])) {
492
    $cache = $page->context_cache[$cache_name];
493
  }
494
  else {
495
    $cache = ctools_context_handler_get_task_object($form_state['task'], $form_state['subtask'], $form_state['handler']);
496
    $form_state['page']->context_cache[$cache_name] = $cache;
497
  }
498

    
499
  $form['right'] = array(
500
    '#prefix' => '<div class="clearfix"><div class="right-container">',
501
    '#suffix' => '</div>',
502
  );
503

    
504
  $form['left'] = array(
505
    '#prefix' => '<div class="left-container">',
506
    '#suffix' => '</div></div>',
507
  );
508

    
509
  $module = 'page_manager_context::' . $page->task_name;
510
  ctools_context_add_context_form($module, $form, $form_state, $form['right']['contexts_table'], $cache);
511
  ctools_context_add_relationship_form($module, $form, $form_state, $form['right']['relationships_table'], $cache);
512

    
513
  $theme_vars = array();
514
  $theme_vars['object'] = $cache;
515
  $theme_vars['header'] = t('Summary of contexts');
516
  $form['left']['summary'] = array(
517
    '#prefix' => '<div class="page-manager-contexts">',
518
    '#suffix' => '</div>',
519
    '#markup' => theme('ctools_context_list', $theme_vars),
520
  );
521

    
522
  $form_state['context_object'] = &$cache;
523
  return $form;
524
}
525

    
526
/**
527
 * Process submission of the context edit form.
528
 */
529
function ctools_context_handler_edit_context_submit(&$form, &$form_state) {
530
  $handler = &$form_state['handler'];
531

    
532
  $cache_name = $handler->name ? $handler->name : 'temp';
533

    
534
  $handler->conf['contexts'] = $form_state['context_object']->contexts;
535
  $handler->conf['relationships'] = $form_state['context_object']->relationships;
536
  if (isset($form_state['page']->context_cache[$cache_name])) {
537
    unset($form_state['page']->context_cache[$cache_name]);
538
  }
539
}
540