annotate sites/all/modules/ctools/includes/context.inc @ 0:ff03f76ab3fe

initial version
author danieleb <danielebarchiesi@me.com>
date Wed, 21 Aug 2013 18:51:11 +0100
parents
children
rev   line source
danielebarchiesi@0 1 <?php
danielebarchiesi@0 2
danielebarchiesi@0 3 /**
danielebarchiesi@0 4 * @file
danielebarchiesi@0 5 *
danielebarchiesi@0 6 * Contains code related to the ctools system of 'context'.
danielebarchiesi@0 7 *
danielebarchiesi@0 8 * Context, originally from Panels, is a method of packaging objects into
danielebarchiesi@0 9 * a more generic bundle and providing a plugin system so that a UI can
danielebarchiesi@0 10 * take advantage of them. The idea is that the context objects
danielebarchiesi@0 11 * represent 'the context' that a given operation (usually a page view)
danielebarchiesi@0 12 * is operating in or on.
danielebarchiesi@0 13 *
danielebarchiesi@0 14 * For example, when viewing a page, the 'context' is a node object. When
danielebarchiesi@0 15 * viewing a user, the 'context' is a user object. Contexts can also
danielebarchiesi@0 16 * have related contexts. For example, when viewing a 'node' you may need
danielebarchiesi@0 17 * to know something about the node author. Therefore, the node author
danielebarchiesi@0 18 * is a related context.
danielebarchiesi@0 19 */
danielebarchiesi@0 20
danielebarchiesi@0 21 /**
danielebarchiesi@0 22 * The context object is largely a wrapper around some other object, with
danielebarchiesi@0 23 * an interface to finding out what is contained and getting to both
danielebarchiesi@0 24 * the object and information about the object.
danielebarchiesi@0 25 *
danielebarchiesi@0 26 * Each context object has its own information, but some things are very
danielebarchiesi@0 27 * common, such as titles, data, keywords, etc. In particulare, the 'type'
danielebarchiesi@0 28 * of the context is important.
danielebarchiesi@0 29 */
danielebarchiesi@0 30 class ctools_context {
danielebarchiesi@0 31 var $type = NULL;
danielebarchiesi@0 32 var $data = NULL;
danielebarchiesi@0 33 // The title of this object.
danielebarchiesi@0 34 var $title = '';
danielebarchiesi@0 35 // The title of the page if this object exists
danielebarchiesi@0 36 var $page_title = '';
danielebarchiesi@0 37 // The identifier (in the UI) of this object
danielebarchiesi@0 38 var $identifier = '';
danielebarchiesi@0 39 var $argument = NULL;
danielebarchiesi@0 40 var $keyword = '';
danielebarchiesi@0 41 var $original_argument = NULL;
danielebarchiesi@0 42 var $restrictions = array();
danielebarchiesi@0 43 var $empty = FALSE;
danielebarchiesi@0 44
danielebarchiesi@0 45 function ctools_context($type = 'none', $data = NULL) {
danielebarchiesi@0 46 $this->type = $type;
danielebarchiesi@0 47 $this->data = $data;
danielebarchiesi@0 48 $this->title = t('Unknown context');
danielebarchiesi@0 49 }
danielebarchiesi@0 50
danielebarchiesi@0 51 function is_type($type) {
danielebarchiesi@0 52 if ($type == 'any' || $this->type == 'any') {
danielebarchiesi@0 53 return TRUE;
danielebarchiesi@0 54 }
danielebarchiesi@0 55
danielebarchiesi@0 56 $a = is_array($type) ? $type : array($type);
danielebarchiesi@0 57 $b = is_array($this->type) ? $this->type : array($this->type);
danielebarchiesi@0 58 return (bool) array_intersect($a, $b);
danielebarchiesi@0 59 }
danielebarchiesi@0 60
danielebarchiesi@0 61 function get_argument() {
danielebarchiesi@0 62 return $this->argument;
danielebarchiesi@0 63 }
danielebarchiesi@0 64
danielebarchiesi@0 65 function get_original_argument() {
danielebarchiesi@0 66 if (!is_null($this->original_argument)) {
danielebarchiesi@0 67 return $this->original_argument;
danielebarchiesi@0 68 }
danielebarchiesi@0 69 return $this->argument;
danielebarchiesi@0 70 }
danielebarchiesi@0 71
danielebarchiesi@0 72 function get_keyword() {
danielebarchiesi@0 73 return $this->keyword;
danielebarchiesi@0 74 }
danielebarchiesi@0 75
danielebarchiesi@0 76 function get_identifier() {
danielebarchiesi@0 77 return $this->identifier;
danielebarchiesi@0 78 }
danielebarchiesi@0 79
danielebarchiesi@0 80 function get_title() {
danielebarchiesi@0 81 return $this->title;
danielebarchiesi@0 82 }
danielebarchiesi@0 83
danielebarchiesi@0 84 function get_page_title() {
danielebarchiesi@0 85 return $this->page_title;
danielebarchiesi@0 86 }
danielebarchiesi@0 87 }
danielebarchiesi@0 88
danielebarchiesi@0 89 /**
danielebarchiesi@0 90 * Used to create a method of comparing if a list of contexts
danielebarchiesi@0 91 * match a required context type.
danielebarchiesi@0 92 */
danielebarchiesi@0 93 class ctools_context_required {
danielebarchiesi@0 94 var $keywords = '';
danielebarchiesi@0 95
danielebarchiesi@0 96 /**
danielebarchiesi@0 97 * If set, the title will be used in the selector to identify
danielebarchiesi@0 98 * the context. This is very useful when multiple contexts
danielebarchiesi@0 99 * are required to inform the user will be used for what.
danielebarchiesi@0 100 */
danielebarchiesi@0 101 var $title = NULL;
danielebarchiesi@0 102
danielebarchiesi@0 103 /**
danielebarchiesi@0 104 * Test to see if this context is required.
danielebarchiesi@0 105 */
danielebarchiesi@0 106 var $required = TRUE;
danielebarchiesi@0 107
danielebarchiesi@0 108 /**
danielebarchiesi@0 109 * If TRUE, skip the check in ctools_context_required::select()
danielebarchiesi@0 110 * for contexts whose names may have changed.
danielebarchiesi@0 111 */
danielebarchiesi@0 112 var $skip_name_check = FALSE;
danielebarchiesi@0 113
danielebarchiesi@0 114 /**
danielebarchiesi@0 115 *
danielebarchiesi@0 116 * @param $title
danielebarchiesi@0 117 * The first parameter should be the 'title' of the context for use
danielebarchiesi@0 118 * in UYI selectors when multiple contexts qualify.
danielebarchiesi@0 119 * @param ...
danielebarchiesi@0 120 * One or more keywords to use for matching which contexts are allowed.
danielebarchiesi@0 121 */
danielebarchiesi@0 122 function ctools_context_required($title) {
danielebarchiesi@0 123 $args = func_get_args();
danielebarchiesi@0 124 $this->title = array_shift($args);
danielebarchiesi@0 125
danielebarchiesi@0 126 // If we have a boolean value at the end for $skip_name_check, store it
danielebarchiesi@0 127 if (is_bool(end($args))) {
danielebarchiesi@0 128 $this->skip_name_check = array_pop($args);
danielebarchiesi@0 129 }
danielebarchiesi@0 130
danielebarchiesi@0 131 // If we were given restrictions at the end, store them.
danielebarchiesi@0 132 if (count($args) > 1 && is_array(end($args))) {
danielebarchiesi@0 133 $this->restrictions = array_pop($args);
danielebarchiesi@0 134 }
danielebarchiesi@0 135
danielebarchiesi@0 136 if (count($args) == 1) {
danielebarchiesi@0 137 $args = array_shift($args);
danielebarchiesi@0 138 }
danielebarchiesi@0 139 $this->keywords = $args;
danielebarchiesi@0 140 }
danielebarchiesi@0 141
danielebarchiesi@0 142 function filter($contexts) {
danielebarchiesi@0 143 $result = array();
danielebarchiesi@0 144
danielebarchiesi@0 145 // See which of these contexts are valid
danielebarchiesi@0 146 foreach ((array) $contexts as $cid => $context) {
danielebarchiesi@0 147 if ($context->is_type($this->keywords)) {
danielebarchiesi@0 148 // Compare to see if our contexts were met.
danielebarchiesi@0 149 if (!empty($this->restrictions) && !empty($context->restrictions)) {
danielebarchiesi@0 150 foreach ($this->restrictions as $key => $values) {
danielebarchiesi@0 151 // If we have a restriction, the context must either not have that
danielebarchiesi@0 152 // restriction listed, which means we simply don't know what it is,
danielebarchiesi@0 153 // or there must be an intersection of the restricted values on
danielebarchiesi@0 154 // both sides.
danielebarchiesi@0 155 if (!is_array($values)) {
danielebarchiesi@0 156 $values = array($values);
danielebarchiesi@0 157 }
danielebarchiesi@0 158 if (!empty($context->restrictions[$key]) && !array_intersect($values, $context->restrictions[$key])) {
danielebarchiesi@0 159 continue 2;
danielebarchiesi@0 160 }
danielebarchiesi@0 161 }
danielebarchiesi@0 162 }
danielebarchiesi@0 163 $result[$cid] = $context;
danielebarchiesi@0 164 }
danielebarchiesi@0 165 }
danielebarchiesi@0 166
danielebarchiesi@0 167 return $result;
danielebarchiesi@0 168 }
danielebarchiesi@0 169
danielebarchiesi@0 170 function select($contexts, $context) {
danielebarchiesi@0 171 if (!is_array($contexts)) {
danielebarchiesi@0 172 $contexts = array($contexts);
danielebarchiesi@0 173 }
danielebarchiesi@0 174
danielebarchiesi@0 175 // If we had requested a $context but that $context doesn't exist
danielebarchiesi@0 176 // in our context list, there is a good chance that what happened
danielebarchiesi@0 177 // is our context IDs changed. See if there's another context
danielebarchiesi@0 178 // that satisfies our requirements.
danielebarchiesi@0 179 if (!$this->skip_name_check && !empty($context) && !isset($contexts[$context])) {
danielebarchiesi@0 180 $choices = $this->filter($contexts);
danielebarchiesi@0 181
danielebarchiesi@0 182 // If we got a hit, take the first one that matches.
danielebarchiesi@0 183 if ($choices) {
danielebarchiesi@0 184 $keys = array_keys($choices);
danielebarchiesi@0 185 $context = reset($keys);
danielebarchiesi@0 186 }
danielebarchiesi@0 187 }
danielebarchiesi@0 188
danielebarchiesi@0 189 if (empty($context) || empty($contexts[$context])) {
danielebarchiesi@0 190 return FALSE;
danielebarchiesi@0 191 }
danielebarchiesi@0 192 return $contexts[$context];
danielebarchiesi@0 193 }
danielebarchiesi@0 194 }
danielebarchiesi@0 195
danielebarchiesi@0 196 /**
danielebarchiesi@0 197 * Used to compare to see if a list of contexts match an optional context. This
danielebarchiesi@0 198 * can produce empty contexts to use as placeholders.
danielebarchiesi@0 199 */
danielebarchiesi@0 200 class ctools_context_optional extends ctools_context_required {
danielebarchiesi@0 201 var $required = FALSE;
danielebarchiesi@0 202 function ctools_context_optional() {
danielebarchiesi@0 203 $args = func_get_args();
danielebarchiesi@0 204 call_user_func_array(array($this, 'ctools_context_required'), $args);
danielebarchiesi@0 205 }
danielebarchiesi@0 206
danielebarchiesi@0 207 /**
danielebarchiesi@0 208 * Add the 'empty' context which is possible for optional
danielebarchiesi@0 209 */
danielebarchiesi@0 210 function add_empty(&$contexts) {
danielebarchiesi@0 211 $context = new ctools_context('any');
danielebarchiesi@0 212 $context->title = t('No context');
danielebarchiesi@0 213 $context->identifier = t('No context');
danielebarchiesi@0 214 $contexts = array_merge(array('empty' => $context), $contexts);
danielebarchiesi@0 215 }
danielebarchiesi@0 216
danielebarchiesi@0 217 function filter($contexts) {
danielebarchiesi@0 218 $this->add_empty($contexts);
danielebarchiesi@0 219 return parent::filter($contexts);
danielebarchiesi@0 220 }
danielebarchiesi@0 221
danielebarchiesi@0 222 function select($contexts, $context) {
danielebarchiesi@0 223 $this->add_empty($contexts);
danielebarchiesi@0 224 if (empty($context)) {
danielebarchiesi@0 225 return $contexts['empty'];
danielebarchiesi@0 226 }
danielebarchiesi@0 227
danielebarchiesi@0 228 $result = parent::select($contexts, $context);
danielebarchiesi@0 229
danielebarchiesi@0 230 // Don't flip out if it can't find the context; this is optional, put
danielebarchiesi@0 231 // in an empty.
danielebarchiesi@0 232 if ($result == FALSE) {
danielebarchiesi@0 233 $result = $contexts['empty'];
danielebarchiesi@0 234 }
danielebarchiesi@0 235 return $result;
danielebarchiesi@0 236 }
danielebarchiesi@0 237 }
danielebarchiesi@0 238
danielebarchiesi@0 239 /**
danielebarchiesi@0 240 * Return a keyed array of context that match the given 'required context'
danielebarchiesi@0 241 * filters.
danielebarchiesi@0 242 *
danielebarchiesi@0 243 * Functions or systems that require contexts of a particular type provide a
danielebarchiesi@0 244 * ctools_context_required or ctools_context_optional object. This function
danielebarchiesi@0 245 * examines that object and an array of contexts to determine which contexts
danielebarchiesi@0 246 * match the filter.
danielebarchiesi@0 247 *
danielebarchiesi@0 248 * Since multiple contexts can be required, this function will accept either
danielebarchiesi@0 249 * an array of all required contexts, or just a single required context object.
danielebarchiesi@0 250 *
danielebarchiesi@0 251 * @param $contexts
danielebarchiesi@0 252 * A keyed array of all available contexts.
danielebarchiesi@0 253 * @param $required
danielebarchiesi@0 254 * A ctools_context_required or ctools_context_optional object, or an array
danielebarchiesi@0 255 * of such objects.
danielebarchiesi@0 256 *
danielebarchiesi@0 257 * @return
danielebarchiesi@0 258 * A keyed array of contexts that match the filter.
danielebarchiesi@0 259 */
danielebarchiesi@0 260 function ctools_context_filter($contexts, $required) {
danielebarchiesi@0 261 if (is_array($required)) {
danielebarchiesi@0 262 $result = array();
danielebarchiesi@0 263 foreach ($required as $r) {
danielebarchiesi@0 264 $result = array_merge($result, _ctools_context_filter($contexts, $r));
danielebarchiesi@0 265 }
danielebarchiesi@0 266 return $result;
danielebarchiesi@0 267 }
danielebarchiesi@0 268
danielebarchiesi@0 269 return _ctools_context_filter($contexts, $required);
danielebarchiesi@0 270 }
danielebarchiesi@0 271
danielebarchiesi@0 272 function _ctools_context_filter($contexts, $required) {
danielebarchiesi@0 273 $result = array();
danielebarchiesi@0 274
danielebarchiesi@0 275 if (is_object($required)) {
danielebarchiesi@0 276 $result = $required->filter($contexts);
danielebarchiesi@0 277 }
danielebarchiesi@0 278
danielebarchiesi@0 279 return $result;
danielebarchiesi@0 280 }
danielebarchiesi@0 281
danielebarchiesi@0 282 /**
danielebarchiesi@0 283 * Create a select box to choose possible contexts.
danielebarchiesi@0 284 *
danielebarchiesi@0 285 * This only creates a selector if there is actually a choice; if there
danielebarchiesi@0 286 * is only one possible context, that one is silently assigned.
danielebarchiesi@0 287 *
danielebarchiesi@0 288 * If an array of required contexts is provided, one selector will be
danielebarchiesi@0 289 * provided for each context.
danielebarchiesi@0 290 *
danielebarchiesi@0 291 * @param $contexts
danielebarchiesi@0 292 * A keyed array of all available contexts.
danielebarchiesi@0 293 * @param $required
danielebarchiesi@0 294 * The required context object or array of objects.
danielebarchiesi@0 295 *
danielebarchiesi@0 296 * @return
danielebarchiesi@0 297 * A form element, or NULL if there are no contexts that satisfy the
danielebarchiesi@0 298 * requirements.
danielebarchiesi@0 299 */
danielebarchiesi@0 300 function ctools_context_selector($contexts, $required, $default) {
danielebarchiesi@0 301 if (is_array($required)) {
danielebarchiesi@0 302 $result = array('#tree' => TRUE);
danielebarchiesi@0 303 $count = 1;
danielebarchiesi@0 304 foreach ($required as $id => $r) {
danielebarchiesi@0 305 $result[] = _ctools_context_selector($contexts, $r, isset($default[$id]) ? $default[$id] : '', $count++);
danielebarchiesi@0 306 }
danielebarchiesi@0 307 return $result;
danielebarchiesi@0 308 }
danielebarchiesi@0 309
danielebarchiesi@0 310 return _ctools_context_selector($contexts, $required, $default);
danielebarchiesi@0 311 }
danielebarchiesi@0 312
danielebarchiesi@0 313 function _ctools_context_selector($contexts, $required, $default, $num = 0) {
danielebarchiesi@0 314 $filtered = ctools_context_filter($contexts, $required);
danielebarchiesi@0 315 $count = count($filtered);
danielebarchiesi@0 316
danielebarchiesi@0 317 $form = array();
danielebarchiesi@0 318
danielebarchiesi@0 319 if ($count >= 1) {
danielebarchiesi@0 320 // If there's more than one to choose from, create a select widget.
danielebarchiesi@0 321 foreach ($filtered as $cid => $context) {
danielebarchiesi@0 322 $options[$cid] = $context->get_identifier();
danielebarchiesi@0 323 }
danielebarchiesi@0 324 if (!empty($required->title)) {
danielebarchiesi@0 325 $title = $required->title;
danielebarchiesi@0 326 }
danielebarchiesi@0 327 else {
danielebarchiesi@0 328 $title = $num ? t('Context %count', array('%count' => $num)) : t('Context');
danielebarchiesi@0 329 }
danielebarchiesi@0 330
danielebarchiesi@0 331 return array(
danielebarchiesi@0 332 '#type' => 'select',
danielebarchiesi@0 333 '#options' => $options,
danielebarchiesi@0 334 '#title' => $title,
danielebarchiesi@0 335 '#default_value' => $default,
danielebarchiesi@0 336 );
danielebarchiesi@0 337 }
danielebarchiesi@0 338 }
danielebarchiesi@0 339
danielebarchiesi@0 340 /**
danielebarchiesi@0 341 * Are there enough contexts for a plugin?
danielebarchiesi@0 342 *
danielebarchiesi@0 343 * Some plugins can have a 'required contexts' item which can either
danielebarchiesi@0 344 * be a context requirement object or an array of them. When contexts
danielebarchiesi@0 345 * are required, items that do not have enough contexts should not
danielebarchiesi@0 346 * appear. This tests an item to see if it has enough contexts
danielebarchiesi@0 347 * to actually appear.
danielebarchiesi@0 348 *
danielebarchiesi@0 349 * @param $contexts
danielebarchiesi@0 350 * A keyed array of all available contexts.
danielebarchiesi@0 351 * @param $required
danielebarchiesi@0 352 * The required context object or array of objects.
danielebarchiesi@0 353 *
danielebarchiesi@0 354 * @return
danielebarchiesi@0 355 * TRUE if there are enough contexts, FALSE if there are not.
danielebarchiesi@0 356 */
danielebarchiesi@0 357 function ctools_context_match_requirements($contexts, $required) {
danielebarchiesi@0 358 if (!is_array($required)) {
danielebarchiesi@0 359 $required = array($required);
danielebarchiesi@0 360 }
danielebarchiesi@0 361
danielebarchiesi@0 362 // Get the keys to avoid bugs in PHP 5.0.8 with keys and loops.
danielebarchiesi@0 363 // And use it to remove optional contexts.
danielebarchiesi@0 364 $keys = array_keys($required);
danielebarchiesi@0 365 foreach ($keys as $key) {
danielebarchiesi@0 366 if (empty($required[$key]->required)) {
danielebarchiesi@0 367 unset($required[$key]);
danielebarchiesi@0 368 }
danielebarchiesi@0 369 }
danielebarchiesi@0 370
danielebarchiesi@0 371 $count = count($required);
danielebarchiesi@0 372 return (count(ctools_context_filter($contexts, $required)) >= $count);
danielebarchiesi@0 373 }
danielebarchiesi@0 374
danielebarchiesi@0 375 /**
danielebarchiesi@0 376 * Create a select box to choose possible contexts.
danielebarchiesi@0 377 *
danielebarchiesi@0 378 * This only creates a selector if there is actually a choice; if there
danielebarchiesi@0 379 * is only one possible context, that one is silently assigned.
danielebarchiesi@0 380 *
danielebarchiesi@0 381 * If an array of required contexts is provided, one selector will be
danielebarchiesi@0 382 * provided for each context.
danielebarchiesi@0 383 *
danielebarchiesi@0 384 * @param $contexts
danielebarchiesi@0 385 * A keyed array of all available contexts.
danielebarchiesi@0 386 * @param $required
danielebarchiesi@0 387 * The required context object or array of objects.
danielebarchiesi@0 388 *
danielebarchiesi@0 389 * @return
danielebarchiesi@0 390 * A form element, or NULL if there are no contexts that satisfy the
danielebarchiesi@0 391 * requirements.
danielebarchiesi@0 392 */
danielebarchiesi@0 393 function ctools_context_converter_selector($contexts, $required, $default) {
danielebarchiesi@0 394 if (is_array($required)) {
danielebarchiesi@0 395 $result = array('#tree' => TRUE);
danielebarchiesi@0 396 $count = 1;
danielebarchiesi@0 397 foreach ($required as $id => $r) {
danielebarchiesi@0 398 $result[] = _ctools_context_converter_selector($contexts, $r, isset($default[$id]) ? $default[$id] : '', $count++);
danielebarchiesi@0 399 }
danielebarchiesi@0 400 return $result;
danielebarchiesi@0 401 }
danielebarchiesi@0 402
danielebarchiesi@0 403 return _ctools_context_converter_selector($contexts, $required, $default);
danielebarchiesi@0 404 }
danielebarchiesi@0 405
danielebarchiesi@0 406 function _ctools_context_converter_selector($contexts, $required, $default, $num = 0) {
danielebarchiesi@0 407 $filtered = ctools_context_filter($contexts, $required);
danielebarchiesi@0 408 $count = count($filtered);
danielebarchiesi@0 409
danielebarchiesi@0 410 $form = array();
danielebarchiesi@0 411
danielebarchiesi@0 412 if ($count > 1) {
danielebarchiesi@0 413 // If there's more than one to choose from, create a select widget.
danielebarchiesi@0 414 $options = array();
danielebarchiesi@0 415 foreach ($filtered as $cid => $context) {
danielebarchiesi@0 416 if ($context->type == 'any') {
danielebarchiesi@0 417 $options[''] = t('No context');
danielebarchiesi@0 418 continue;
danielebarchiesi@0 419 }
danielebarchiesi@0 420 $key = $context->get_identifier();
danielebarchiesi@0 421 if ($converters = ctools_context_get_converters($cid . '.', $context)) {
danielebarchiesi@0 422 $options[$key] = $converters;
danielebarchiesi@0 423 }
danielebarchiesi@0 424 }
danielebarchiesi@0 425 if (empty($options)) {
danielebarchiesi@0 426 return array(
danielebarchiesi@0 427 '#type' => 'value',
danielebarchiesi@0 428 '#value' => 'any',
danielebarchiesi@0 429 );
danielebarchiesi@0 430 }
danielebarchiesi@0 431 if (!empty($required->title)) {
danielebarchiesi@0 432 $title = $required->title;
danielebarchiesi@0 433 }
danielebarchiesi@0 434 else {
danielebarchiesi@0 435 $title = $num ? t('Context %count', array('%count' => $num)) : t('Context');
danielebarchiesi@0 436 }
danielebarchiesi@0 437
danielebarchiesi@0 438 return array(
danielebarchiesi@0 439 '#type' => 'select',
danielebarchiesi@0 440 '#options' => $options,
danielebarchiesi@0 441 '#title' => $title,
danielebarchiesi@0 442 '#description' => t('Please choose which context and how you would like it converted.'),
danielebarchiesi@0 443 '#default_value' => $default,
danielebarchiesi@0 444 );
danielebarchiesi@0 445 }
danielebarchiesi@0 446 }
danielebarchiesi@0 447
danielebarchiesi@0 448 /**
danielebarchiesi@0 449 * Get a list of converters available for a given context.
danielebarchiesi@0 450 */
danielebarchiesi@0 451 function ctools_context_get_converters($cid, $context) {
danielebarchiesi@0 452 if (empty($context->plugin)) {
danielebarchiesi@0 453 return array();
danielebarchiesi@0 454 }
danielebarchiesi@0 455
danielebarchiesi@0 456 return _ctools_context_get_converters($cid, $context->plugin);
danielebarchiesi@0 457 }
danielebarchiesi@0 458
danielebarchiesi@0 459 /**
danielebarchiesi@0 460 * Get a list of converters available for a given context.
danielebarchiesi@0 461 */
danielebarchiesi@0 462 function _ctools_context_get_converters($id, $plugin_name) {
danielebarchiesi@0 463 $plugin = ctools_get_context($plugin_name);
danielebarchiesi@0 464 if (empty($plugin['convert list'])) {
danielebarchiesi@0 465 return array();
danielebarchiesi@0 466 }
danielebarchiesi@0 467
danielebarchiesi@0 468 $converters = array();
danielebarchiesi@0 469 if (is_array($plugin['convert list'])) {
danielebarchiesi@0 470 $converters = $plugin['convert list'];
danielebarchiesi@0 471 }
danielebarchiesi@0 472 else if ($function = ctools_plugin_get_function($plugin, 'convert list')) {
danielebarchiesi@0 473 $converters = (array) $function($plugin);
danielebarchiesi@0 474 }
danielebarchiesi@0 475
danielebarchiesi@0 476 foreach (module_implements('ctools_context_convert_list_alter') as $module) {
danielebarchiesi@0 477 $function = $module . '_ctools_context_convert_list_alter';
danielebarchiesi@0 478 $function($plugin, $converters);
danielebarchiesi@0 479 }
danielebarchiesi@0 480
danielebarchiesi@0 481 // Now, change them all to include the plugin:
danielebarchiesi@0 482 $return = array();
danielebarchiesi@0 483 foreach ($converters as $key => $title) {
danielebarchiesi@0 484 $return[$id . $key] = $title;
danielebarchiesi@0 485 }
danielebarchiesi@0 486
danielebarchiesi@0 487 natcasesort($return);
danielebarchiesi@0 488 return $return;
danielebarchiesi@0 489 }
danielebarchiesi@0 490
danielebarchiesi@0 491 /**
danielebarchiesi@0 492 * Get a list of all contexts + converters available.
danielebarchiesi@0 493 */
danielebarchiesi@0 494 function ctools_context_get_all_converters() {
danielebarchiesi@0 495 $contexts = ctools_get_contexts();
danielebarchiesi@0 496 $converters = array();
danielebarchiesi@0 497 foreach ($contexts as $name => $context) {
danielebarchiesi@0 498 if (empty($context['no required context ui'])) {
danielebarchiesi@0 499 $context_converters = _ctools_context_get_converters($name . '.', $name);
danielebarchiesi@0 500 if ($context_converters) {
danielebarchiesi@0 501 $converters[$context['title']] = $context_converters;
danielebarchiesi@0 502 }
danielebarchiesi@0 503 }
danielebarchiesi@0 504 }
danielebarchiesi@0 505
danielebarchiesi@0 506 return $converters;
danielebarchiesi@0 507 }
danielebarchiesi@0 508
danielebarchiesi@0 509 /**
danielebarchiesi@0 510 * Let the context convert an argument based upon the converter that was given.
danielebarchiesi@0 511 *
danielebarchiesi@0 512 * @param $context
danielebarchiesi@0 513 * The context object
danielebarchiesi@0 514 * @param $converter
danielebarchiesi@0 515 * The converter to use, which should be a string provided by the converter list.
danielebarchiesi@0 516 * @param $converter_options
danielebarchiesi@0 517 * A n array of options to pass on to the generation function. For contexts
danielebarchiesi@0 518 * that use token module, of particular use is 'sanitize' => FALSE which can
danielebarchiesi@0 519 * get raw tokens. This should ONLY be used in values that will later be
danielebarchiesi@0 520 * treated as unsafe user input since these values are by themselves unsafe.
danielebarchiesi@0 521 * It is particularly useful to get raw values from Field API.
danielebarchiesi@0 522 */
danielebarchiesi@0 523 function ctools_context_convert_context($context, $converter, $converter_options = array()) {
danielebarchiesi@0 524 // Contexts without plugins might be optional placeholders.
danielebarchiesi@0 525 if (empty($context->plugin)) {
danielebarchiesi@0 526 return;
danielebarchiesi@0 527 }
danielebarchiesi@0 528
danielebarchiesi@0 529 $value = $context->argument;
danielebarchiesi@0 530 $plugin = ctools_get_context($context->plugin);
danielebarchiesi@0 531 if ($function = ctools_plugin_get_function($plugin, 'convert')) {
danielebarchiesi@0 532 $value = $function($context, $converter, $converter_options);
danielebarchiesi@0 533 }
danielebarchiesi@0 534
danielebarchiesi@0 535 foreach (module_implements('ctools_context_converter_alter') as $module) {
danielebarchiesi@0 536 $function = $module . '_ctools_context_converter_alter';
danielebarchiesi@0 537 $function($context, $converter, $value, $converter_options);
danielebarchiesi@0 538 }
danielebarchiesi@0 539
danielebarchiesi@0 540 return $value;
danielebarchiesi@0 541 }
danielebarchiesi@0 542
danielebarchiesi@0 543 /**
danielebarchiesi@0 544 * Choose a context or contexts based upon the selection made via
danielebarchiesi@0 545 * ctools_context_filter.
danielebarchiesi@0 546 *
danielebarchiesi@0 547 * @param $contexts
danielebarchiesi@0 548 * A keyed array of all available contexts
danielebarchiesi@0 549 * @param $required
danielebarchiesi@0 550 * The required context object provided by the plugin
danielebarchiesi@0 551 * @param $context
danielebarchiesi@0 552 * The selection made using ctools_context_selector
danielebarchiesi@0 553 */
danielebarchiesi@0 554 function ctools_context_select($contexts, $required, $context) {
danielebarchiesi@0 555 if (is_array($required)) {
danielebarchiesi@0 556 $result = array();
danielebarchiesi@0 557 foreach ($required as $id => $r) {
danielebarchiesi@0 558 if (empty($required[$id])) {
danielebarchiesi@0 559 continue;
danielebarchiesi@0 560 }
danielebarchiesi@0 561
danielebarchiesi@0 562 if (($result[] = _ctools_context_select($contexts, $r, $context[$id])) === FALSE) {
danielebarchiesi@0 563 return FALSE;
danielebarchiesi@0 564 }
danielebarchiesi@0 565 }
danielebarchiesi@0 566 return $result;
danielebarchiesi@0 567 }
danielebarchiesi@0 568
danielebarchiesi@0 569 return _ctools_context_select($contexts, $required, $context);
danielebarchiesi@0 570 }
danielebarchiesi@0 571
danielebarchiesi@0 572 function _ctools_context_select($contexts, $required, $context) {
danielebarchiesi@0 573 if (!is_object($required)) {
danielebarchiesi@0 574 return FALSE;
danielebarchiesi@0 575 }
danielebarchiesi@0 576
danielebarchiesi@0 577 return $required->select($contexts, $context);
danielebarchiesi@0 578 }
danielebarchiesi@0 579
danielebarchiesi@0 580 /**
danielebarchiesi@0 581 * Create a new context object.
danielebarchiesi@0 582 *
danielebarchiesi@0 583 * @param $type
danielebarchiesi@0 584 * The type of context to create; this loads a plugin.
danielebarchiesi@0 585 * @param $data
danielebarchiesi@0 586 * The data to put into the context.
danielebarchiesi@0 587 * @param $empty
danielebarchiesi@0 588 * Whether or not this context is specifically empty.
danielebarchiesi@0 589 * @param $conf
danielebarchiesi@0 590 * A configuration structure if this context was created via UI.
danielebarchiesi@0 591 *
danielebarchiesi@0 592 * @return
danielebarchiesi@0 593 * A $context or NULL if one could not be created.
danielebarchiesi@0 594 */
danielebarchiesi@0 595 function ctools_context_create($type, $data = NULL, $conf = FALSE) {
danielebarchiesi@0 596 ctools_include('plugins');
danielebarchiesi@0 597 $plugin = ctools_get_context($type);
danielebarchiesi@0 598
danielebarchiesi@0 599 if ($function = ctools_plugin_get_function($plugin, 'context')) {
danielebarchiesi@0 600 return $function(FALSE, $data, $conf, $plugin);
danielebarchiesi@0 601 }
danielebarchiesi@0 602 }
danielebarchiesi@0 603
danielebarchiesi@0 604 /**
danielebarchiesi@0 605 * Create an empty context object.
danielebarchiesi@0 606 *
danielebarchiesi@0 607 * Empty context objects are primarily used as placeholders in the UI where
danielebarchiesi@0 608 * the actual contents of a context object may not be known. It may have
danielebarchiesi@0 609 * additional text embedded to give the user clues as to how the context
danielebarchiesi@0 610 * is used.
danielebarchiesi@0 611 *
danielebarchiesi@0 612 * @param $type
danielebarchiesi@0 613 * The type of context to create; this loads a plugin.
danielebarchiesi@0 614 *
danielebarchiesi@0 615 * @return
danielebarchiesi@0 616 * A $context or NULL if one could not be created.
danielebarchiesi@0 617 */
danielebarchiesi@0 618 function ctools_context_create_empty($type) {
danielebarchiesi@0 619 $plugin = ctools_get_context($type);
danielebarchiesi@0 620 if ($function = ctools_plugin_get_function($plugin, 'context')) {
danielebarchiesi@0 621 $context = $function(TRUE, NULL, FALSE, $plugin);
danielebarchiesi@0 622 if (is_object($context)) {
danielebarchiesi@0 623 $context->empty = TRUE;
danielebarchiesi@0 624 }
danielebarchiesi@0 625
danielebarchiesi@0 626 return $context;
danielebarchiesi@0 627 }
danielebarchiesi@0 628 }
danielebarchiesi@0 629
danielebarchiesi@0 630 /**
danielebarchiesi@0 631 * Perform keyword and context substitutions.
danielebarchiesi@0 632 */
danielebarchiesi@0 633 function ctools_context_keyword_substitute($string, $keywords, $contexts, $converter_options = array()) {
danielebarchiesi@0 634 // Ensure a default keyword exists:
danielebarchiesi@0 635 $keywords['%%'] = '%';
danielebarchiesi@0 636
danielebarchiesi@0 637 // Match contexts to the base keywords:
danielebarchiesi@0 638 $context_keywords = array();
danielebarchiesi@0 639 foreach ($contexts as $context) {
danielebarchiesi@0 640 if (isset($context->keyword)) {
danielebarchiesi@0 641 $context_keywords[$context->keyword] = $context;
danielebarchiesi@0 642 }
danielebarchiesi@0 643 }
danielebarchiesi@0 644
danielebarchiesi@0 645 // Look for context matches we we only have to convert known matches.
danielebarchiesi@0 646 $matches = array();
danielebarchiesi@0 647 if (preg_match_all('/%(%|[a-zA-Z0-9_-]+(?:\:[a-zA-Z0-9_-]+)*)/us', $string, $matches)) {
danielebarchiesi@0 648 foreach ($matches[1] as $keyword) {
danielebarchiesi@0 649 // Ignore anything it finds with %%.
danielebarchiesi@0 650 if ($keyword[0] == '%') {
danielebarchiesi@0 651 continue;
danielebarchiesi@0 652 }
danielebarchiesi@0 653
danielebarchiesi@0 654 // If the keyword is already set by something passed in, don't try to
danielebarchiesi@0 655 // overwrite it.
danielebarchiesi@0 656 if (!empty($keywords['%' . $keyword])) {
danielebarchiesi@0 657 continue;
danielebarchiesi@0 658 }
danielebarchiesi@0 659
danielebarchiesi@0 660 // Figure out our keyword and converter, if specified.
danielebarchiesi@0 661 if (strpos($keyword, ':')) {
danielebarchiesi@0 662 list($context, $converter) = explode(':', $keyword, 2);
danielebarchiesi@0 663 }
danielebarchiesi@0 664 else {
danielebarchiesi@0 665 $context = $keyword;
danielebarchiesi@0 666 if (isset($context_keywords[$keyword])) {
danielebarchiesi@0 667 $plugin = ctools_get_context($context_keywords[$context]->plugin);
danielebarchiesi@0 668
danielebarchiesi@0 669 // Fall back to a default converter, if specified.
danielebarchiesi@0 670 if ($plugin && !empty($plugin['convert default'])) {
danielebarchiesi@0 671 $converter = $plugin['convert default'];
danielebarchiesi@0 672 }
danielebarchiesi@0 673 }
danielebarchiesi@0 674 }
danielebarchiesi@0 675
danielebarchiesi@0 676 if (empty($context_keywords[$context]) || !empty($context_keywords[$context]->empty)) {
danielebarchiesi@0 677 $keywords['%' . $keyword] = '';
danielebarchiesi@0 678 }
danielebarchiesi@0 679 else if (!empty($converter)) {
danielebarchiesi@0 680 $keywords['%' . $keyword] = ctools_context_convert_context($context_keywords[$context], $converter, $converter_options);
danielebarchiesi@0 681 }
danielebarchiesi@0 682 else {
danielebarchiesi@0 683 $keywords['%' . $keyword] = $context_keywords[$keyword]->title;
danielebarchiesi@0 684 }
danielebarchiesi@0 685 }
danielebarchiesi@0 686 }
danielebarchiesi@0 687 return strtr($string, $keywords);
danielebarchiesi@0 688 }
danielebarchiesi@0 689
danielebarchiesi@0 690 /**
danielebarchiesi@0 691 * Determine a unique context ID for a context
danielebarchiesi@0 692 *
danielebarchiesi@0 693 * Often contexts of many different types will be placed into a list. This
danielebarchiesi@0 694 * ensures that even though contexts of multiple types may share IDs, they
danielebarchiesi@0 695 * are unique in the final list.
danielebarchiesi@0 696 */
danielebarchiesi@0 697 function ctools_context_id($context, $type = 'context') {
danielebarchiesi@0 698 if (!$context['id']) {
danielebarchiesi@0 699 $context['id'] = 1;
danielebarchiesi@0 700 }
danielebarchiesi@0 701
danielebarchiesi@0 702 return $type . '_' . $context['name'] . '_' . $context['id'];
danielebarchiesi@0 703 }
danielebarchiesi@0 704
danielebarchiesi@0 705 /**
danielebarchiesi@0 706 * Get the next id available given a list of already existing objects.
danielebarchiesi@0 707 *
danielebarchiesi@0 708 * This finds the next id available for the named object.
danielebarchiesi@0 709 *
danielebarchiesi@0 710 * @param $objects
danielebarchiesi@0 711 * A list of context descriptor objects, i.e, arguments, relationships, contexts, etc.
danielebarchiesi@0 712 * @param $name
danielebarchiesi@0 713 * The name being used.
danielebarchiesi@0 714 */
danielebarchiesi@0 715 function ctools_context_next_id($objects, $name) {
danielebarchiesi@0 716 $id = 0;
danielebarchiesi@0 717 // Figure out which instance of this argument we're creating
danielebarchiesi@0 718 if (!$objects) {
danielebarchiesi@0 719 return $id + 1;
danielebarchiesi@0 720 }
danielebarchiesi@0 721
danielebarchiesi@0 722 foreach ($objects as $object) {
danielebarchiesi@0 723 if (isset($object['name']) && $object['name'] == $name) {
danielebarchiesi@0 724 if ($object['id'] > $id) {
danielebarchiesi@0 725 $id = $object['id'];
danielebarchiesi@0 726 }
danielebarchiesi@0 727 }
danielebarchiesi@0 728 }
danielebarchiesi@0 729
danielebarchiesi@0 730 return $id + 1;
danielebarchiesi@0 731 }
danielebarchiesi@0 732
danielebarchiesi@0 733
danielebarchiesi@0 734 // ---------------------------------------------------------------------------
danielebarchiesi@0 735 // Functions related to contexts from arguments.
danielebarchiesi@0 736
danielebarchiesi@0 737 /**
danielebarchiesi@0 738 * Fetch metadata on a specific argument plugin.
danielebarchiesi@0 739 *
danielebarchiesi@0 740 * @param $argument
danielebarchiesi@0 741 * Name of an argument plugin.
danielebarchiesi@0 742 *
danielebarchiesi@0 743 * @return
danielebarchiesi@0 744 * An array with information about the requested argument plugin.
danielebarchiesi@0 745 */
danielebarchiesi@0 746 function ctools_get_argument($argument) {
danielebarchiesi@0 747 ctools_include('plugins');
danielebarchiesi@0 748 return ctools_get_plugins('ctools', 'arguments', $argument);
danielebarchiesi@0 749 }
danielebarchiesi@0 750
danielebarchiesi@0 751 /**
danielebarchiesi@0 752 * Fetch metadata for all argument plugins.
danielebarchiesi@0 753 *
danielebarchiesi@0 754 * @return
danielebarchiesi@0 755 * An array of arrays with information about all available argument plugins.
danielebarchiesi@0 756 */
danielebarchiesi@0 757 function ctools_get_arguments() {
danielebarchiesi@0 758 ctools_include('plugins');
danielebarchiesi@0 759 return ctools_get_plugins('ctools', 'arguments');
danielebarchiesi@0 760 }
danielebarchiesi@0 761
danielebarchiesi@0 762 /**
danielebarchiesi@0 763 * Get a context from an argument.
danielebarchiesi@0 764 *
danielebarchiesi@0 765 * @param $argument
danielebarchiesi@0 766 * The configuration of an argument. It must contain the following data:
danielebarchiesi@0 767 * - name: The name of the argument plugin being used.
danielebarchiesi@0 768 * - argument_settings: The configuration based upon the plugin forms.
danielebarchiesi@0 769 * - identifier: The human readable identifier for this argument, usually
danielebarchiesi@0 770 * defined by the UI.
danielebarchiesi@0 771 * - keyword: The keyword used for this argument for substitutions.
danielebarchiesi@0 772 *
danielebarchiesi@0 773 * @param $arg
danielebarchiesi@0 774 * The actual argument received. This is expected to be a string from a URL but
danielebarchiesi@0 775 * this does not have to be the only source of arguments.
danielebarchiesi@0 776 * @param $empty
danielebarchiesi@0 777 * If true, the $arg will not be used to load the context. Instead, an empty
danielebarchiesi@0 778 * placeholder context will be loaded.
danielebarchiesi@0 779 *
danielebarchiesi@0 780 * @return
danielebarchiesi@0 781 * A context object if one can be loaded.
danielebarchiesi@0 782 */
danielebarchiesi@0 783 function ctools_context_get_context_from_argument($argument, $arg, $empty = FALSE) {
danielebarchiesi@0 784 ctools_include('plugins');
danielebarchiesi@0 785 if (empty($argument['name'])) {
danielebarchiesi@0 786 return;
danielebarchiesi@0 787 }
danielebarchiesi@0 788
danielebarchiesi@0 789 if ($function = ctools_plugin_load_function('ctools', 'arguments', $argument['name'], 'context')) {
danielebarchiesi@0 790 // Backward compatibility: Merge old style settings into new style:
danielebarchiesi@0 791 if (!empty($argument['settings'])) {
danielebarchiesi@0 792 $argument += $argument['settings'];
danielebarchiesi@0 793 unset($argument['settings']);
danielebarchiesi@0 794 }
danielebarchiesi@0 795
danielebarchiesi@0 796 $context = $function($arg, $argument, $empty);
danielebarchiesi@0 797
danielebarchiesi@0 798 if (is_object($context)) {
danielebarchiesi@0 799 $context->identifier = $argument['identifier'];
danielebarchiesi@0 800 $context->page_title = isset($argument['title']) ? $argument['title'] : '';
danielebarchiesi@0 801 $context->keyword = $argument['keyword'];
danielebarchiesi@0 802 $context->id = ctools_context_id($argument, 'argument');
danielebarchiesi@0 803 $context->original_argument = $arg;
danielebarchiesi@0 804
danielebarchiesi@0 805 if (!empty($context->empty)) {
danielebarchiesi@0 806 $context->placeholder = array(
danielebarchiesi@0 807 'type' => 'argument',
danielebarchiesi@0 808 'conf' => $argument,
danielebarchiesi@0 809 );
danielebarchiesi@0 810 }
danielebarchiesi@0 811 }
danielebarchiesi@0 812 return $context;
danielebarchiesi@0 813 }
danielebarchiesi@0 814 }
danielebarchiesi@0 815
danielebarchiesi@0 816 /**
danielebarchiesi@0 817 * Retrieve a list of empty contexts for all arguments.
danielebarchiesi@0 818 */
danielebarchiesi@0 819 function ctools_context_get_placeholders_from_argument($arguments) {
danielebarchiesi@0 820 $contexts = array();
danielebarchiesi@0 821 foreach ($arguments as $argument) {
danielebarchiesi@0 822 $context = ctools_context_get_context_from_argument($argument, NULL, TRUE);
danielebarchiesi@0 823 if ($context) {
danielebarchiesi@0 824 $contexts[ctools_context_id($argument, 'argument')] = $context;
danielebarchiesi@0 825 }
danielebarchiesi@0 826 }
danielebarchiesi@0 827 return $contexts;
danielebarchiesi@0 828 }
danielebarchiesi@0 829
danielebarchiesi@0 830 /**
danielebarchiesi@0 831 * Load the contexts for a given list of arguments.
danielebarchiesi@0 832 *
danielebarchiesi@0 833 * @param $arguments
danielebarchiesi@0 834 * The array of argument definitions.
danielebarchiesi@0 835 * @param &$contexts
danielebarchiesi@0 836 * The array of existing contexts. New contexts will be added to this array.
danielebarchiesi@0 837 * @param $args
danielebarchiesi@0 838 * The arguments to load.
danielebarchiesi@0 839 *
danielebarchiesi@0 840 * @return
danielebarchiesi@0 841 * FALSE if an argument wants to 404.
danielebarchiesi@0 842 */
danielebarchiesi@0 843 function ctools_context_get_context_from_arguments($arguments, &$contexts, $args) {
danielebarchiesi@0 844 foreach ($arguments as $argument) {
danielebarchiesi@0 845 // pull the argument off the list.
danielebarchiesi@0 846 $arg = array_shift($args);
danielebarchiesi@0 847 $id = ctools_context_id($argument, 'argument');
danielebarchiesi@0 848
danielebarchiesi@0 849 // For % arguments embedded in the URL, our context is already loaded.
danielebarchiesi@0 850 // There is no need to go and load it again.
danielebarchiesi@0 851 if (empty($contexts[$id])) {
danielebarchiesi@0 852 if ($context = ctools_context_get_context_from_argument($argument, $arg)) {
danielebarchiesi@0 853 $contexts[$id] = $context;
danielebarchiesi@0 854 }
danielebarchiesi@0 855 }
danielebarchiesi@0 856 else {
danielebarchiesi@0 857 $context = $contexts[$id];
danielebarchiesi@0 858 }
danielebarchiesi@0 859
danielebarchiesi@0 860 if ((empty($context) || empty($context->data)) && !empty($argument['default']) && $argument['default'] == '404') {
danielebarchiesi@0 861 return FALSE;
danielebarchiesi@0 862 }
danielebarchiesi@0 863 }
danielebarchiesi@0 864 return TRUE;
danielebarchiesi@0 865 }
danielebarchiesi@0 866
danielebarchiesi@0 867 // ---------------------------------------------------------------------------
danielebarchiesi@0 868 // Functions related to contexts from relationships.
danielebarchiesi@0 869
danielebarchiesi@0 870 /**
danielebarchiesi@0 871 * Fetch metadata on a specific relationship plugin.
danielebarchiesi@0 872 *
danielebarchiesi@0 873 * @param $content type
danielebarchiesi@0 874 * Name of a panel content type.
danielebarchiesi@0 875 *
danielebarchiesi@0 876 * @return
danielebarchiesi@0 877 * An array with information about the requested relationship.
danielebarchiesi@0 878 */
danielebarchiesi@0 879 function ctools_get_relationship($relationship) {
danielebarchiesi@0 880 ctools_include('plugins');
danielebarchiesi@0 881 return ctools_get_plugins('ctools', 'relationships', $relationship);
danielebarchiesi@0 882 }
danielebarchiesi@0 883
danielebarchiesi@0 884 /**
danielebarchiesi@0 885 * Fetch metadata for all relationship plugins.
danielebarchiesi@0 886 *
danielebarchiesi@0 887 * @return
danielebarchiesi@0 888 * An array of arrays with information about all available relationships.
danielebarchiesi@0 889 */
danielebarchiesi@0 890 function ctools_get_relationships() {
danielebarchiesi@0 891 ctools_include('plugins');
danielebarchiesi@0 892 return ctools_get_plugins('ctools', 'relationships');
danielebarchiesi@0 893 }
danielebarchiesi@0 894
danielebarchiesi@0 895 /**
danielebarchiesi@0 896 *
danielebarchiesi@0 897 * @param $relationship
danielebarchiesi@0 898 * The configuration of a relationship. It must contain the following data:
danielebarchiesi@0 899 * - name: The name of the relationship plugin being used.
danielebarchiesi@0 900 * - relationship_settings: The configuration based upon the plugin forms.
danielebarchiesi@0 901 * - identifier: The human readable identifier for this relationship, usually
danielebarchiesi@0 902 * defined by the UI.
danielebarchiesi@0 903 * - keyword: The keyword used for this relationship for substitutions.
danielebarchiesi@0 904 *
danielebarchiesi@0 905 * @param $source_context
danielebarchiesi@0 906 * The context this relationship is based upon.
danielebarchiesi@0 907 *
danielebarchiesi@0 908 * @param $placeholders
danielebarchiesi@0 909 * If TRUE, placeholders are acceptable.
danielebarchiesi@0 910 *
danielebarchiesi@0 911 * @return
danielebarchiesi@0 912 * A context object if one can be loaded.
danielebarchiesi@0 913 */
danielebarchiesi@0 914 function ctools_context_get_context_from_relationship($relationship, $source_context, $placeholders = FALSE) {
danielebarchiesi@0 915 ctools_include('plugins');
danielebarchiesi@0 916 if ($function = ctools_plugin_load_function('ctools', 'relationships', $relationship['name'], 'context')) {
danielebarchiesi@0 917 // Backward compatibility: Merge old style settings into new style:
danielebarchiesi@0 918 if (!empty($relationship['relationship_settings'])) {
danielebarchiesi@0 919 $relationship += $relationship['relationship_settings'];
danielebarchiesi@0 920 unset($relationship['relationship_settings']);
danielebarchiesi@0 921 }
danielebarchiesi@0 922
danielebarchiesi@0 923 $context = $function($source_context, $relationship, $placeholders);
danielebarchiesi@0 924 if ($context) {
danielebarchiesi@0 925 $context->identifier = $relationship['identifier'];
danielebarchiesi@0 926 $context->page_title = isset($relationship['title']) ? $relationship['title'] : '';
danielebarchiesi@0 927 $context->keyword = $relationship['keyword'];
danielebarchiesi@0 928 if (!empty($context->empty)) {
danielebarchiesi@0 929 $context->placeholder = array(
danielebarchiesi@0 930 'type' => 'relationship',
danielebarchiesi@0 931 'conf' => $relationship,
danielebarchiesi@0 932 );
danielebarchiesi@0 933 }
danielebarchiesi@0 934 return $context;
danielebarchiesi@0 935 }
danielebarchiesi@0 936 }
danielebarchiesi@0 937 }
danielebarchiesi@0 938
danielebarchiesi@0 939 /**
danielebarchiesi@0 940 * Fetch all relevant relationships.
danielebarchiesi@0 941 *
danielebarchiesi@0 942 * Relevant relationships are any relationship that can be created based upon
danielebarchiesi@0 943 * the list of existing contexts. For example, the 'node author' relationship
danielebarchiesi@0 944 * is relevant if there is a 'node' context, but makes no sense if there is
danielebarchiesi@0 945 * not one.
danielebarchiesi@0 946 *
danielebarchiesi@0 947 * @param $contexts
danielebarchiesi@0 948 * An array of contexts used to figure out which relationships are relevant.
danielebarchiesi@0 949 *
danielebarchiesi@0 950 * @return
danielebarchiesi@0 951 * An array of relationship keys that are relevant for the given set of
danielebarchiesi@0 952 * contexts.
danielebarchiesi@0 953 */
danielebarchiesi@0 954 function ctools_context_get_relevant_relationships($contexts) {
danielebarchiesi@0 955 $relevant = array();
danielebarchiesi@0 956 $relationships = ctools_get_relationships();
danielebarchiesi@0 957
danielebarchiesi@0 958 // Go through each relationship
danielebarchiesi@0 959 foreach ($relationships as $rid => $relationship) {
danielebarchiesi@0 960 // For each relationship, see if there is a context that satisfies it.
danielebarchiesi@0 961 if (empty($relationship['no ui']) && ctools_context_filter($contexts, $relationship['required context'])) {
danielebarchiesi@0 962 $relevant[$rid] = $relationship['title'];
danielebarchiesi@0 963 }
danielebarchiesi@0 964 }
danielebarchiesi@0 965
danielebarchiesi@0 966 return $relevant;
danielebarchiesi@0 967 }
danielebarchiesi@0 968
danielebarchiesi@0 969 /**
danielebarchiesi@0 970 * Fetch all active relationships
danielebarchiesi@0 971 *
danielebarchiesi@0 972 * @param $relationships
danielebarchiesi@0 973 * An keyed array of relationship data including:
danielebarchiesi@0 974 * - name: name of relationship
danielebarchiesi@0 975 * - context: context id relationship belongs to. This will be used to
danielebarchiesi@0 976 * identify which context in the $contexts array to use to create the
danielebarchiesi@0 977 * relationship context.
danielebarchiesi@0 978 *
danielebarchiesi@0 979 * @param $contexts
danielebarchiesi@0 980 * A keyed array of contexts used to figure out which relationships
danielebarchiesi@0 981 * are relevant. New contexts will be added to this.
danielebarchiesi@0 982 *
danielebarchiesi@0 983 * @param $placeholders
danielebarchiesi@0 984 * If TRUE, placeholders are acceptable.
danielebarchiesi@0 985 */
danielebarchiesi@0 986 function ctools_context_get_context_from_relationships($relationships, &$contexts, $placeholders = FALSE) {
danielebarchiesi@0 987 $return = array();
danielebarchiesi@0 988
danielebarchiesi@0 989 foreach ($relationships as $rdata) {
danielebarchiesi@0 990 if (!isset($rdata['context'])) {
danielebarchiesi@0 991 continue;
danielebarchiesi@0 992 }
danielebarchiesi@0 993
danielebarchiesi@0 994 if (is_array($rdata['context'])) {
danielebarchiesi@0 995 $rcontexts = array();
danielebarchiesi@0 996 foreach ($rdata['context'] as $cid) {
danielebarchiesi@0 997 if (empty($contexts[$cid])) {
danielebarchiesi@0 998 continue 2;
danielebarchiesi@0 999 }
danielebarchiesi@0 1000 $rcontexts[] = $contexts[$cid];
danielebarchiesi@0 1001 }
danielebarchiesi@0 1002 }
danielebarchiesi@0 1003 else {
danielebarchiesi@0 1004 if (empty($contexts[$rdata['context']])) {
danielebarchiesi@0 1005 continue;
danielebarchiesi@0 1006 }
danielebarchiesi@0 1007 $rcontexts = $contexts[$rdata['context']];
danielebarchiesi@0 1008 }
danielebarchiesi@0 1009
danielebarchiesi@0 1010 $cid = ctools_context_id($rdata, 'relationship');
danielebarchiesi@0 1011 if ($context = ctools_context_get_context_from_relationship($rdata, $rcontexts)) {
danielebarchiesi@0 1012 $contexts[$cid] = $context;
danielebarchiesi@0 1013 }
danielebarchiesi@0 1014 }
danielebarchiesi@0 1015 }
danielebarchiesi@0 1016
danielebarchiesi@0 1017 // ---------------------------------------------------------------------------
danielebarchiesi@0 1018 // Functions related to loading contexts from simple context definitions.
danielebarchiesi@0 1019
danielebarchiesi@0 1020 /**
danielebarchiesi@0 1021 * Fetch metadata on a specific context plugin.
danielebarchiesi@0 1022 *
danielebarchiesi@0 1023 * @param $context
danielebarchiesi@0 1024 * Name of a context.
danielebarchiesi@0 1025 *
danielebarchiesi@0 1026 * @return
danielebarchiesi@0 1027 * An array with information about the requested panel context.
danielebarchiesi@0 1028 */
danielebarchiesi@0 1029 function ctools_get_context($context) {
danielebarchiesi@0 1030 static $gate = array();
danielebarchiesi@0 1031 ctools_include('plugins');
danielebarchiesi@0 1032 $plugin = ctools_get_plugins('ctools', 'contexts', $context);
danielebarchiesi@0 1033 if (empty($gate['context']) && !empty($plugin['superceded by'])) {
danielebarchiesi@0 1034 // This gate prevents infinite loops.
danielebarchiesi@0 1035 $gate[$context] = TRUE;
danielebarchiesi@0 1036 $new_plugin = ctools_get_plugins('ctools', 'contexts', $plugin['superceded by']);
danielebarchiesi@0 1037 $gate[$context] = FALSE;
danielebarchiesi@0 1038
danielebarchiesi@0 1039 // If a new plugin was returned, return it. Otherwise fall through and
danielebarchiesi@0 1040 // return the original we fetched.
danielebarchiesi@0 1041 if ($new_plugin) {
danielebarchiesi@0 1042 return $new_plugin;
danielebarchiesi@0 1043 }
danielebarchiesi@0 1044 }
danielebarchiesi@0 1045
danielebarchiesi@0 1046 return $plugin;
danielebarchiesi@0 1047 }
danielebarchiesi@0 1048
danielebarchiesi@0 1049 /**
danielebarchiesi@0 1050 * Fetch metadata for all context plugins.
danielebarchiesi@0 1051 *
danielebarchiesi@0 1052 * @return
danielebarchiesi@0 1053 * An array of arrays with information about all available panel contexts.
danielebarchiesi@0 1054 */
danielebarchiesi@0 1055 function ctools_get_contexts() {
danielebarchiesi@0 1056 ctools_include('plugins');
danielebarchiesi@0 1057 return ctools_get_plugins('ctools', 'contexts');
danielebarchiesi@0 1058 }
danielebarchiesi@0 1059
danielebarchiesi@0 1060 /**
danielebarchiesi@0 1061 *
danielebarchiesi@0 1062 * @param $context
danielebarchiesi@0 1063 * The configuration of a context. It must contain the following data:
danielebarchiesi@0 1064 * - name: The name of the context plugin being used.
danielebarchiesi@0 1065 * - context_settings: The configuration based upon the plugin forms.
danielebarchiesi@0 1066 * - identifier: The human readable identifier for this context, usually
danielebarchiesi@0 1067 * defined by the UI.
danielebarchiesi@0 1068 * - keyword: The keyword used for this context for substitutions.
danielebarchiesi@0 1069 * @param $type
danielebarchiesi@0 1070 * This is either 'context' which indicates the context will be loaded
danielebarchiesi@0 1071 * from data in the settings, or 'required_context' which means the
danielebarchiesi@0 1072 * context must be acquired from an external source. This is the method
danielebarchiesi@0 1073 * used to pass pure contexts from one system to another.
danielebarchiesi@0 1074 *
danielebarchiesi@0 1075 * @return
danielebarchiesi@0 1076 * A context object if one can be loaded.
danielebarchiesi@0 1077 */
danielebarchiesi@0 1078 function ctools_context_get_context_from_context($context, $type = 'context', $argument = NULL) {
danielebarchiesi@0 1079 ctools_include('plugins');
danielebarchiesi@0 1080 $plugin = ctools_get_context($context['name']);
danielebarchiesi@0 1081 if ($function = ctools_plugin_get_function($plugin, 'context')) {
danielebarchiesi@0 1082 // Backward compatibility: Merge old style settings into new style:
danielebarchiesi@0 1083 if (!empty($context['context_settings'])) {
danielebarchiesi@0 1084 $context += $context['context_settings'];
danielebarchiesi@0 1085 unset($context['context_settings']);
danielebarchiesi@0 1086 }
danielebarchiesi@0 1087
danielebarchiesi@0 1088 if (isset($argument) && isset($plugin['placeholder name'])) {
danielebarchiesi@0 1089 $context[$plugin['placeholder name']] = $argument;
danielebarchiesi@0 1090 }
danielebarchiesi@0 1091
danielebarchiesi@0 1092 $return = $function($type == 'requiredcontext', $context, TRUE, $plugin);
danielebarchiesi@0 1093 if ($return) {
danielebarchiesi@0 1094 $return->identifier = $context['identifier'];
danielebarchiesi@0 1095 $return->page_title = isset($context['title']) ? $context['title'] : '';
danielebarchiesi@0 1096 $return->keyword = $context['keyword'];
danielebarchiesi@0 1097
danielebarchiesi@0 1098 if (!empty($context->empty)) {
danielebarchiesi@0 1099 $context->placeholder = array(
danielebarchiesi@0 1100 'type' => 'context',
danielebarchiesi@0 1101 'conf' => $context,
danielebarchiesi@0 1102 );
danielebarchiesi@0 1103 }
danielebarchiesi@0 1104
danielebarchiesi@0 1105 return $return;
danielebarchiesi@0 1106 }
danielebarchiesi@0 1107 }
danielebarchiesi@0 1108 }
danielebarchiesi@0 1109
danielebarchiesi@0 1110 /**
danielebarchiesi@0 1111 * Retrieve a list of base contexts based upon a simple 'contexts' definition.
danielebarchiesi@0 1112 *
danielebarchiesi@0 1113 * For required contexts this will always retrieve placeholders.
danielebarchiesi@0 1114 *
danielebarchiesi@0 1115 * @param $contexts
danielebarchiesi@0 1116 * The list of contexts defined in the UI.
danielebarchiesi@0 1117 * @param $type
danielebarchiesi@0 1118 * Either 'context' or 'requiredcontext', which indicates whether the contexts
danielebarchiesi@0 1119 * are loaded from internal data or copied from an external source.
danielebarchiesi@0 1120 * @param $placeholders
danielebarchiesi@0 1121 * If true, placeholders are acceptable.
danielebarchiesi@0 1122 */
danielebarchiesi@0 1123 function ctools_context_get_context_from_contexts($contexts, $type = 'context', $placeholders = FALSE) {
danielebarchiesi@0 1124 $return = array();
danielebarchiesi@0 1125 foreach ($contexts as $context) {
danielebarchiesi@0 1126 $ctext = ctools_context_get_context_from_context($context, $type);
danielebarchiesi@0 1127 if ($ctext) {
danielebarchiesi@0 1128 if ($placeholders) {
danielebarchiesi@0 1129 $ctext->placeholder = TRUE;
danielebarchiesi@0 1130 }
danielebarchiesi@0 1131 $return[ctools_context_id($context, $type)] = $ctext;
danielebarchiesi@0 1132 }
danielebarchiesi@0 1133 }
danielebarchiesi@0 1134 return $return;
danielebarchiesi@0 1135 }
danielebarchiesi@0 1136
danielebarchiesi@0 1137 /**
danielebarchiesi@0 1138 * Match up external contexts to our required contexts.
danielebarchiesi@0 1139 *
danielebarchiesi@0 1140 * This function is used to create a list of contexts with proper
danielebarchiesi@0 1141 * IDs based upon a list of required contexts.
danielebarchiesi@0 1142 *
danielebarchiesi@0 1143 * These contexts passed in should match the numeric positions of the
danielebarchiesi@0 1144 * required contexts. The caller must ensure this has already happened
danielebarchiesi@0 1145 * correctly as this function will not detect errors here.
danielebarchiesi@0 1146 *
danielebarchiesi@0 1147 * @param $required
danielebarchiesi@0 1148 * A list of required contexts as defined by the UI.
danielebarchiesi@0 1149 * @param $contexts
danielebarchiesi@0 1150 * A list of matching contexts as passed in from the calling system.
danielebarchiesi@0 1151 */
danielebarchiesi@0 1152 function ctools_context_match_required_contexts($required, $contexts) {
danielebarchiesi@0 1153 $return = array();
danielebarchiesi@0 1154 if (!is_array($required)) {
danielebarchiesi@0 1155 return $return;
danielebarchiesi@0 1156 }
danielebarchiesi@0 1157
danielebarchiesi@0 1158 foreach ($required as $r) {
danielebarchiesi@0 1159 $context = clone(array_shift($contexts));
danielebarchiesi@0 1160 $context->identifier = $r['identifier'];
danielebarchiesi@0 1161 $context->page_title = isset($r['title']) ? $r['title'] : '';
danielebarchiesi@0 1162 $context->keyword = $r['keyword'];
danielebarchiesi@0 1163 $return[ctools_context_id($r, 'requiredcontext')] = $context;
danielebarchiesi@0 1164 }
danielebarchiesi@0 1165
danielebarchiesi@0 1166 return $return;
danielebarchiesi@0 1167 }
danielebarchiesi@0 1168
danielebarchiesi@0 1169 /**
danielebarchiesi@0 1170 * Load a full array of contexts for an object.
danielebarchiesi@0 1171 *
danielebarchiesi@0 1172 * Not all of the types need to be supported by this object.
danielebarchiesi@0 1173 *
danielebarchiesi@0 1174 * This function is not used to load contexts from external data, but may
danielebarchiesi@0 1175 * be used to load internal contexts and relationships. Otherwise it can also
danielebarchiesi@0 1176 * be used to generate a full set of placeholders for UI purposes.
danielebarchiesi@0 1177 *
danielebarchiesi@0 1178 * @param $object
danielebarchiesi@0 1179 * An object that contains some or all of the following variables:
danielebarchiesi@0 1180 *
danielebarchiesi@0 1181 * - requiredcontexts: A list of UI configured contexts that are required
danielebarchiesi@0 1182 * from an external source. Since these require external data, they will
danielebarchiesi@0 1183 * only be added if $placeholders is set to TRUE, and empty contexts will
danielebarchiesi@0 1184 * be created.
danielebarchiesi@0 1185 * - arguments: A list of UI configured arguments that will create contexts.
danielebarchiesi@0 1186 * Since these require external data, they will only be added if $placeholders
danielebarchiesi@0 1187 * is set to TRUE.
danielebarchiesi@0 1188 * - contexts: A list of UI configured contexts that have no external source,
danielebarchiesi@0 1189 * and are essentially hardcoded. For example, these might configure a
danielebarchiesi@0 1190 * particular node or a particular taxonomy term.
danielebarchiesi@0 1191 * - relationships: A list of UI configured contexts to be derived from other
danielebarchiesi@0 1192 * contexts that already exist from other sources. For example, these might
danielebarchiesi@0 1193 * be used to get a user object from a node via the node author relationship.
danielebarchiesi@0 1194 * @param $placeholders
danielebarchiesi@0 1195 * If TRUE, this will generate placeholder objects for types this function
danielebarchiesi@0 1196 * cannot load.
danielebarchiesi@0 1197 * @param $contexts
danielebarchiesi@0 1198 * An array of pre-existing contexts that will be part of the return value.
danielebarchiesi@0 1199 */
danielebarchiesi@0 1200 function ctools_context_load_contexts($object, $placeholders = TRUE, $contexts = array()) {
danielebarchiesi@0 1201 if (!empty($object->base_contexts)) {
danielebarchiesi@0 1202 $contexts += $object->base_contexts;
danielebarchiesi@0 1203 }
danielebarchiesi@0 1204
danielebarchiesi@0 1205 if ($placeholders) {
danielebarchiesi@0 1206 // This will load empty contexts as placeholders for arguments that come
danielebarchiesi@0 1207 // from external sources. If this isn't set, it's assumed these context
danielebarchiesi@0 1208 // will already have been matched up and loaded.
danielebarchiesi@0 1209 if (!empty($object->requiredcontexts) && is_array($object->requiredcontexts)) {
danielebarchiesi@0 1210 $contexts += ctools_context_get_context_from_contexts($object->requiredcontexts, 'requiredcontext', $placeholders);
danielebarchiesi@0 1211 }
danielebarchiesi@0 1212
danielebarchiesi@0 1213 if (!empty($object->arguments) && is_array($object->arguments)) {
danielebarchiesi@0 1214 $contexts += ctools_context_get_placeholders_from_argument($object->arguments);
danielebarchiesi@0 1215 }
danielebarchiesi@0 1216 }
danielebarchiesi@0 1217
danielebarchiesi@0 1218 if (!empty($object->contexts) && is_array($object->contexts)) {
danielebarchiesi@0 1219 $contexts += ctools_context_get_context_from_contexts($object->contexts, 'context', $placeholders);
danielebarchiesi@0 1220 }
danielebarchiesi@0 1221
danielebarchiesi@0 1222 // add contexts from relationships
danielebarchiesi@0 1223 if (!empty($object->relationships) && is_array($object->relationships)) {
danielebarchiesi@0 1224 ctools_context_get_context_from_relationships($object->relationships, $contexts, $placeholders);
danielebarchiesi@0 1225 }
danielebarchiesi@0 1226
danielebarchiesi@0 1227 return $contexts;
danielebarchiesi@0 1228 }
danielebarchiesi@0 1229
danielebarchiesi@0 1230 /**
danielebarchiesi@0 1231 * Return the first context with a form id from a list of contexts.
danielebarchiesi@0 1232 *
danielebarchiesi@0 1233 * This function is used to figure out which contexts represents 'the form'
danielebarchiesi@0 1234 * from a list of contexts. Only one contexts can actually be 'the form' for
danielebarchiesi@0 1235 * a given page, since the @code{<form>} tag can not be embedded within
danielebarchiesi@0 1236 * itself.
danielebarchiesi@0 1237 */
danielebarchiesi@0 1238 function ctools_context_get_form($contexts) {
danielebarchiesi@0 1239 if (!empty($contexts)) {
danielebarchiesi@0 1240 foreach ($contexts as $id => $context) {
danielebarchiesi@0 1241 // if a form shows its id as being a 'required context' that means the
danielebarchiesi@0 1242 // the context is external to this display and does not count.
danielebarchiesi@0 1243 if (!empty($context->form_id) && substr($id, 0, 15) != 'requiredcontext') {
danielebarchiesi@0 1244 return $context;
danielebarchiesi@0 1245 }
danielebarchiesi@0 1246 }
danielebarchiesi@0 1247 }
danielebarchiesi@0 1248 }
danielebarchiesi@0 1249
danielebarchiesi@0 1250 /**
danielebarchiesi@0 1251 * Replace placeholders with real contexts using data extracted from a form
danielebarchiesi@0 1252 * for the purposes of previews.
danielebarchiesi@0 1253 *
danielebarchiesi@0 1254 * @param $contexts
danielebarchiesi@0 1255 * All of the contexts, including the placeholders.
danielebarchiesi@0 1256 * @param $arguments
danielebarchiesi@0 1257 * The arguments. These will be acquired from $form_state['values'] and the
danielebarchiesi@0 1258 * keys must match the context IDs.
danielebarchiesi@0 1259 *
danielebarchiesi@0 1260 * @return
danielebarchiesi@0 1261 * A new $contexts array containing the replaced contexts. Not all contexts
danielebarchiesi@0 1262 * may be replaced if, for example, an argument was unable to be converted
danielebarchiesi@0 1263 * into a context.
danielebarchiesi@0 1264 */
danielebarchiesi@0 1265 function ctools_context_replace_placeholders($contexts, $arguments) {
danielebarchiesi@0 1266 foreach ($contexts as $cid => $context) {
danielebarchiesi@0 1267 if (empty($context->empty)) {
danielebarchiesi@0 1268 continue;
danielebarchiesi@0 1269 }
danielebarchiesi@0 1270
danielebarchiesi@0 1271 $new_context = NULL;
danielebarchiesi@0 1272 switch ($context->placeholder['type']) {
danielebarchiesi@0 1273 case 'relationship':
danielebarchiesi@0 1274 $relationship = $context->placeholder['conf'];
danielebarchiesi@0 1275 if (isset($contexts[$relationship['context']])) {
danielebarchiesi@0 1276 $new_context = ctools_context_get_context_from_relationship($relationship, $contexts[$relationship['context']]);
danielebarchiesi@0 1277 }
danielebarchiesi@0 1278 break;
danielebarchiesi@0 1279 case 'argument':
danielebarchiesi@0 1280 if (isset($arguments[$cid]) && $arguments[$cid] !== '') {
danielebarchiesi@0 1281 $argument = $context->placeholder['conf'];
danielebarchiesi@0 1282 $new_context = ctools_context_get_context_from_argument($argument, $arguments[$cid]);
danielebarchiesi@0 1283 }
danielebarchiesi@0 1284 break;
danielebarchiesi@0 1285 case 'context':
danielebarchiesi@0 1286 if (!empty($arguments[$cid])) {
danielebarchiesi@0 1287 $context_info = $context->placeholder['conf'];
danielebarchiesi@0 1288 $new_context = ctools_context_get_context_from_context($context_info, 'requiredcontext', $arguments[$cid]);
danielebarchiesi@0 1289 }
danielebarchiesi@0 1290 break;
danielebarchiesi@0 1291 }
danielebarchiesi@0 1292
danielebarchiesi@0 1293 if ($new_context && empty($new_context->empty)) {
danielebarchiesi@0 1294 $contexts[$cid] = $new_context;
danielebarchiesi@0 1295 }
danielebarchiesi@0 1296 }
danielebarchiesi@0 1297
danielebarchiesi@0 1298 return $contexts;
danielebarchiesi@0 1299 }
danielebarchiesi@0 1300
danielebarchiesi@0 1301 /**
danielebarchiesi@0 1302 * Provide a form array for getting data to replace placeholder contexts
danielebarchiesi@0 1303 * with real data.
danielebarchiesi@0 1304 */
danielebarchiesi@0 1305 function ctools_context_replace_form(&$form, $contexts) {
danielebarchiesi@0 1306 foreach ($contexts as $cid => $context) {
danielebarchiesi@0 1307 if (empty($context->empty)) {
danielebarchiesi@0 1308 continue;
danielebarchiesi@0 1309 }
danielebarchiesi@0 1310
danielebarchiesi@0 1311 // Get plugin info from the context which should have been set when the
danielebarchiesi@0 1312 // empty context was created.
danielebarchiesi@0 1313 $info = NULL;
danielebarchiesi@0 1314 $plugin = NULL;
danielebarchiesi@0 1315 $settings = NULL;
danielebarchiesi@0 1316 switch ($context->placeholder['type']) {
danielebarchiesi@0 1317 case 'argument':
danielebarchiesi@0 1318 $info = $context->placeholder['conf'];
danielebarchiesi@0 1319 $plugin = ctools_get_argument($info['name']);
danielebarchiesi@0 1320 break;
danielebarchiesi@0 1321
danielebarchiesi@0 1322 case 'context':
danielebarchiesi@0 1323 $info = $context->placeholder['conf'];
danielebarchiesi@0 1324 $plugin = ctools_get_context($info['name']);
danielebarchiesi@0 1325 break;
danielebarchiesi@0 1326 }
danielebarchiesi@0 1327
danielebarchiesi@0 1328 // Ask the plugin where the form is.
danielebarchiesi@0 1329 if ($plugin && isset($plugin['placeholder form'])) {
danielebarchiesi@0 1330 if (is_array($plugin['placeholder form'])) {
danielebarchiesi@0 1331 $form[$cid] = $plugin['placeholder form'];
danielebarchiesi@0 1332 }
danielebarchiesi@0 1333 else if (function_exists($plugin['placeholder form'])) {
danielebarchiesi@0 1334 $widget = $plugin['placeholder form']($info);
danielebarchiesi@0 1335 if ($widget) {
danielebarchiesi@0 1336 $form[$cid] = $widget;
danielebarchiesi@0 1337 }
danielebarchiesi@0 1338 }
danielebarchiesi@0 1339
danielebarchiesi@0 1340 if (!empty($form[$cid])) {
danielebarchiesi@0 1341 $form[$cid]['#title'] = t('@identifier (@keyword)', array('@keyword' => '%' . $context->keyword, '@identifier' => $context->identifier));
danielebarchiesi@0 1342 }
danielebarchiesi@0 1343 }
danielebarchiesi@0 1344 }
danielebarchiesi@0 1345 }
danielebarchiesi@0 1346
danielebarchiesi@0 1347 // ---------------------------------------------------------------------------
danielebarchiesi@0 1348 // Functions related to loading access control plugins
danielebarchiesi@0 1349
danielebarchiesi@0 1350 /**
danielebarchiesi@0 1351 * Fetch metadata on a specific access control plugin.
danielebarchiesi@0 1352 *
danielebarchiesi@0 1353 * @param $name
danielebarchiesi@0 1354 * Name of a plugin.
danielebarchiesi@0 1355 *
danielebarchiesi@0 1356 * @return
danielebarchiesi@0 1357 * An array with information about the requested access control plugin.
danielebarchiesi@0 1358 */
danielebarchiesi@0 1359 function ctools_get_access_plugin($name) {
danielebarchiesi@0 1360 ctools_include('plugins');
danielebarchiesi@0 1361 return ctools_get_plugins('ctools', 'access', $name);
danielebarchiesi@0 1362 }
danielebarchiesi@0 1363
danielebarchiesi@0 1364 /**
danielebarchiesi@0 1365 * Fetch metadata for all access control plugins.
danielebarchiesi@0 1366 *
danielebarchiesi@0 1367 * @return
danielebarchiesi@0 1368 * An array of arrays with information about all available access control plugins.
danielebarchiesi@0 1369 */
danielebarchiesi@0 1370 function ctools_get_access_plugins() {
danielebarchiesi@0 1371 ctools_include('plugins');
danielebarchiesi@0 1372 return ctools_get_plugins('ctools', 'access');
danielebarchiesi@0 1373 }
danielebarchiesi@0 1374
danielebarchiesi@0 1375 /**
danielebarchiesi@0 1376 * Fetch a list of access plugins that are available for a given list of
danielebarchiesi@0 1377 * contexts.
danielebarchiesi@0 1378 *
danielebarchiesi@0 1379 * if 'logged-in-user' is not in the list of contexts, it will be added as
danielebarchiesi@0 1380 * this is required.
danielebarchiesi@0 1381 */
danielebarchiesi@0 1382 function ctools_get_relevant_access_plugins($contexts) {
danielebarchiesi@0 1383 if (!isset($contexts['logged-in-user'])) {
danielebarchiesi@0 1384 $contexts['logged-in-user'] = ctools_access_get_loggedin_context();
danielebarchiesi@0 1385 }
danielebarchiesi@0 1386
danielebarchiesi@0 1387 $all_plugins = ctools_get_access_plugins();
danielebarchiesi@0 1388 $plugins = array();
danielebarchiesi@0 1389 foreach ($all_plugins as $id => $plugin) {
danielebarchiesi@0 1390 if (!empty($plugin['required context']) && !ctools_context_match_requirements($contexts, $plugin['required context'])) {
danielebarchiesi@0 1391 continue;
danielebarchiesi@0 1392 }
danielebarchiesi@0 1393 $plugins[$id] = $plugin;
danielebarchiesi@0 1394 }
danielebarchiesi@0 1395
danielebarchiesi@0 1396 return $plugins;
danielebarchiesi@0 1397 }
danielebarchiesi@0 1398
danielebarchiesi@0 1399 /**
danielebarchiesi@0 1400 * Create a context for the logged in user.
danielebarchiesi@0 1401 */
danielebarchiesi@0 1402 function ctools_access_get_loggedin_context() {
danielebarchiesi@0 1403 global $user;
danielebarchiesi@0 1404 $context = ctools_context_create('entity:user', $user);
danielebarchiesi@0 1405 $context->identifier = t('Logged in user');
danielebarchiesi@0 1406 $context->keyword = 'viewer';
danielebarchiesi@0 1407 $context->id = 0;
danielebarchiesi@0 1408
danielebarchiesi@0 1409 return $context;
danielebarchiesi@0 1410 }
danielebarchiesi@0 1411
danielebarchiesi@0 1412 /**
danielebarchiesi@0 1413 * Get a summary of an access plugin's settings.
danielebarchiesi@0 1414 */
danielebarchiesi@0 1415 function ctools_access_summary($plugin, $contexts, $test) {
danielebarchiesi@0 1416 if (!isset($contexts['logged-in-user'])) {
danielebarchiesi@0 1417 $contexts['logged-in-user'] = ctools_access_get_loggedin_context();
danielebarchiesi@0 1418 }
danielebarchiesi@0 1419
danielebarchiesi@0 1420 $description = '';
danielebarchiesi@0 1421 if ($function = ctools_plugin_get_function($plugin, 'summary')) {
danielebarchiesi@0 1422 $required_context = isset($plugin['required context']) ? $plugin['required context'] : array();
danielebarchiesi@0 1423 $context = isset($test['context']) ? $test['context'] : array();
danielebarchiesi@0 1424 $description = $function($test['settings'], ctools_context_select($contexts, $required_context, $context), $plugin);
danielebarchiesi@0 1425 }
danielebarchiesi@0 1426
danielebarchiesi@0 1427 if (!empty($test['not'])) {
danielebarchiesi@0 1428 $description = "NOT ($description)";
danielebarchiesi@0 1429 }
danielebarchiesi@0 1430
danielebarchiesi@0 1431 return $description;
danielebarchiesi@0 1432 }
danielebarchiesi@0 1433
danielebarchiesi@0 1434 /**
danielebarchiesi@0 1435 * Get a summary of a group of access plugin's settings.
danielebarchiesi@0 1436 */
danielebarchiesi@0 1437 function ctools_access_group_summary($access, $contexts) {
danielebarchiesi@0 1438 if (empty($access['plugins'])) {
danielebarchiesi@0 1439 return;
danielebarchiesi@0 1440 }
danielebarchiesi@0 1441
danielebarchiesi@0 1442 $descriptions = array();
danielebarchiesi@0 1443 foreach ($access['plugins'] as $id => $test) {
danielebarchiesi@0 1444 $plugin = ctools_get_access_plugin($test['name']);
danielebarchiesi@0 1445 $descriptions[] = ctools_access_summary($plugin, $contexts, $test);
danielebarchiesi@0 1446 }
danielebarchiesi@0 1447
danielebarchiesi@0 1448 $separator = (isset($access['logic']) && $access['logic'] == 'and') ? t(', and ') : t(', or ');
danielebarchiesi@0 1449 return implode($separator, $descriptions);
danielebarchiesi@0 1450 }
danielebarchiesi@0 1451
danielebarchiesi@0 1452 /**
danielebarchiesi@0 1453 * Determine if the current user has access via plugin.
danielebarchiesi@0 1454 *
danielebarchiesi@0 1455 * @param $settings
danielebarchiesi@0 1456 * An array of settings theoretically set by the user.
danielebarchiesi@0 1457 * @param $contexts
danielebarchiesi@0 1458 * An array of zero or more contexts that may be used to determine if
danielebarchiesi@0 1459 * the user has access.
danielebarchiesi@0 1460 *
danielebarchiesi@0 1461 * @return
danielebarchiesi@0 1462 * TRUE if access is granted, false if otherwise.
danielebarchiesi@0 1463 */
danielebarchiesi@0 1464 function ctools_access($settings, $contexts = array()) {
danielebarchiesi@0 1465 if (empty($settings['plugins'])) {
danielebarchiesi@0 1466 return TRUE;
danielebarchiesi@0 1467 }
danielebarchiesi@0 1468
danielebarchiesi@0 1469 if (!isset($settings['logic'])) {
danielebarchiesi@0 1470 $settings['logic'] = 'and';
danielebarchiesi@0 1471 }
danielebarchiesi@0 1472
danielebarchiesi@0 1473 if (!isset($contexts['logged-in-user'])) {
danielebarchiesi@0 1474 $contexts['logged-in-user'] = ctools_access_get_loggedin_context();
danielebarchiesi@0 1475 }
danielebarchiesi@0 1476
danielebarchiesi@0 1477 foreach ($settings['plugins'] as $test) {
danielebarchiesi@0 1478 $pass = FALSE;
danielebarchiesi@0 1479 $plugin = ctools_get_access_plugin($test['name']);
danielebarchiesi@0 1480 if ($plugin && $function = ctools_plugin_get_function($plugin, 'callback')) {
danielebarchiesi@0 1481 // Do we need just some contexts or all of them?
danielebarchiesi@0 1482 if (!empty($plugin['all contexts'])) {
danielebarchiesi@0 1483 $test_contexts = $contexts;
danielebarchiesi@0 1484 }
danielebarchiesi@0 1485 else {
danielebarchiesi@0 1486 $required_context = isset($plugin['required context']) ? $plugin['required context'] : array();
danielebarchiesi@0 1487 $context = isset($test['context']) ? $test['context'] : array();
danielebarchiesi@0 1488 $test_contexts = ctools_context_select($contexts, $required_context, $context);
danielebarchiesi@0 1489 }
danielebarchiesi@0 1490
danielebarchiesi@0 1491 $pass = $function($test['settings'], $test_contexts, $plugin);
danielebarchiesi@0 1492 if (!empty($test['not'])) {
danielebarchiesi@0 1493 $pass = !$pass;
danielebarchiesi@0 1494 }
danielebarchiesi@0 1495 }
danielebarchiesi@0 1496
danielebarchiesi@0 1497 if ($pass && $settings['logic'] == 'or') {
danielebarchiesi@0 1498 // Pass if 'or' and this rule passed.
danielebarchiesi@0 1499 return TRUE;
danielebarchiesi@0 1500 }
danielebarchiesi@0 1501 else if (!$pass && $settings['logic'] == 'and') {
danielebarchiesi@0 1502 // Fail if 'and' and htis rule failed.
danielebarchiesi@0 1503 return FALSE;
danielebarchiesi@0 1504 }
danielebarchiesi@0 1505 }
danielebarchiesi@0 1506
danielebarchiesi@0 1507 // Return TRUE if logic was and, meaning all rules passed.
danielebarchiesi@0 1508 // Return FALSE if logic was or, meaning no rule passed.
danielebarchiesi@0 1509 return $settings['logic'] == 'and';
danielebarchiesi@0 1510 }
danielebarchiesi@0 1511
danielebarchiesi@0 1512 /**
danielebarchiesi@0 1513 * Create default settings for a new access plugin.
danielebarchiesi@0 1514 *
danielebarchiesi@0 1515 * @param $plugin
danielebarchiesi@0 1516 * The access plugin being used.
danielebarchiesi@0 1517 *
danielebarchiesi@0 1518 * @return
danielebarchiesi@0 1519 * A default configured test that should be placed in $access['plugins'];
danielebarchiesi@0 1520 */
danielebarchiesi@0 1521 function ctools_access_new_test($plugin) {
danielebarchiesi@0 1522 $test = array(
danielebarchiesi@0 1523 'name' => $plugin['name'],
danielebarchiesi@0 1524 'settings' => array(),
danielebarchiesi@0 1525 );
danielebarchiesi@0 1526
danielebarchiesi@0 1527 // Set up required context defaults.
danielebarchiesi@0 1528 if (isset($plugin['required context'])) {
danielebarchiesi@0 1529 if (is_object($plugin['required context'])) {
danielebarchiesi@0 1530 $test['context'] = '';
danielebarchiesi@0 1531 }
danielebarchiesi@0 1532 else {
danielebarchiesi@0 1533 $test['context'] = array();
danielebarchiesi@0 1534 foreach ($plugin['required context'] as $required) {
danielebarchiesi@0 1535 $test['context'][] = '';
danielebarchiesi@0 1536 }
danielebarchiesi@0 1537 }
danielebarchiesi@0 1538 }
danielebarchiesi@0 1539
danielebarchiesi@0 1540
danielebarchiesi@0 1541 $default = NULL;
danielebarchiesi@0 1542 if (isset($plugin['default'])) {
danielebarchiesi@0 1543 $default = $plugin['default'];
danielebarchiesi@0 1544 }
danielebarchiesi@0 1545 elseif (isset($plugin['defaults'])) {
danielebarchiesi@0 1546 $default = $plugin['defaults'];
danielebarchiesi@0 1547 }
danielebarchiesi@0 1548
danielebarchiesi@0 1549 // Setup plugin defaults.
danielebarchiesi@0 1550 if (isset($default)) {
danielebarchiesi@0 1551 if (is_array($default)) {
danielebarchiesi@0 1552 $test['settings'] = $default;
danielebarchiesi@0 1553 }
danielebarchiesi@0 1554 else if (function_exists($default)) {
danielebarchiesi@0 1555 $test['settings'] = $default();
danielebarchiesi@0 1556 }
danielebarchiesi@0 1557 else {
danielebarchiesi@0 1558 $test['settings'] = array();
danielebarchiesi@0 1559 }
danielebarchiesi@0 1560 }
danielebarchiesi@0 1561
danielebarchiesi@0 1562 return $test;
danielebarchiesi@0 1563 }
danielebarchiesi@0 1564
danielebarchiesi@0 1565 /**
danielebarchiesi@0 1566 * Apply restrictions to contexts based upon the access control configured.
danielebarchiesi@0 1567 *
danielebarchiesi@0 1568 * These restrictions allow the UI to not show content that may not
danielebarchiesi@0 1569 * be relevant to all types of a particular context.
danielebarchiesi@0 1570 */
danielebarchiesi@0 1571 function ctools_access_add_restrictions($settings, $contexts) {
danielebarchiesi@0 1572 if (empty($settings['plugins'])) {
danielebarchiesi@0 1573 return;
danielebarchiesi@0 1574 }
danielebarchiesi@0 1575
danielebarchiesi@0 1576 if (!isset($settings['logic'])) {
danielebarchiesi@0 1577 $settings['logic'] = 'and';
danielebarchiesi@0 1578 }
danielebarchiesi@0 1579
danielebarchiesi@0 1580 // We're not going to try to figure out restrictions on the or.
danielebarchiesi@0 1581 if ($settings['logic'] == 'or' && count($settings['plugins']) > 1) {
danielebarchiesi@0 1582 return;
danielebarchiesi@0 1583 }
danielebarchiesi@0 1584
danielebarchiesi@0 1585 foreach ($settings['plugins'] as $test) {
danielebarchiesi@0 1586 $plugin = ctools_get_access_plugin($test['name']);
danielebarchiesi@0 1587 if ($plugin && $function = ctools_plugin_get_function($plugin, 'restrictions')) {
danielebarchiesi@0 1588 $required_context = isset($plugin['required context']) ? $plugin['required context'] : array();
danielebarchiesi@0 1589 $context = isset($test['context']) ? $test['context'] : array();
danielebarchiesi@0 1590 $contexts = ctools_context_select($contexts, $required_context, $context);
danielebarchiesi@0 1591 $function($test['settings'], $contexts);
danielebarchiesi@0 1592 }
danielebarchiesi@0 1593 }
danielebarchiesi@0 1594 }