Projet

Général

Profil

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

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

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 task
8
 * handler should use those contexts as selection rules, as well as rendering
9
 * 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
 * Provides 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 object $handler
278
 *   The handler in question.
279
 * @param object $contexts
280
 *   The context objects provided by the task.
281
 *
282
 * @return bool
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 object $task
302
 *   The loaded task plugin.
303
 * @param object $subtask
304
 *   The subtask id.
305
 * @param object $handler
306
 *   The handler to be checked.
307
 *
308
 * @return array
309
 *   Returns array of summary strings for arguments selected by task handlers.
310
 */
311
function ctools_context_handler_summary($task, $subtask, $handler) {
312
  if (empty($handler->conf['access']['plugins'])) {
313
    return array();
314
  }
315

    
316
  ctools_include('context');
317
  $strings = array();
318
  $contexts = ctools_context_handler_get_all_contexts($task, $subtask, $handler);
319

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

    
327
  return $strings;
328
}
329

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

    
347
  return $contexts;
348
}
349

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

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

    
372
  $object = ctools_context_handler_get_task_object($task, $subtask, $handler);
373
  $contexts = ctools_context_load_contexts($object, TRUE, $contexts);
374
  ctools_context_handler_set_access_restrictions($task, $subtask, $handler, $contexts);
375
  return $contexts;
376
}
377

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

    
388
  return $object;
389
}
390

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

    
404
  return $object;
405
}
406

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

    
418
  return array();
419
}
420

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

    
429
  return array();
430
}
431

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

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

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

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

    
477
  $form['markup'] = array(
478
    '#markup' => '<div class="description">' .
479
    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.') .
480
    '</div>',
481
  );
482
  $form = ctools_access_admin_form($form, $form_state);
483
  return $form;
484
}
485

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

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

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

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

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

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

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

    
534
  $form_state['context_object'] = &$cache;
535
  return $form;
536
}
537

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

    
544
  $cache_name = $handler->name ? $handler->name : 'temp';
545

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