plugins.inc

Go to the documentation of this file.
00001 <?php
00002 // $Id: plugins.inc,v 1.1.2.55 2008/11/12 19:58:57 sdboyer Exp $
00003 
00004 
00005 /**
00006  * @file plugins.inc
00007  *
00008  * Contains helper code for plugins and contexts.
00009  */
00010 
00011 /**
00012  * Forms the basis for describing and storing a context that a display
00013  * might be running in.
00014  */
00015 class panels_context {
00016   var $type = NULL;
00017   var $data = NULL;
00018   // The title of this object.
00019   var $title = '';
00020   // The title of the page if this object exists
00021   var $page_title = '';
00022   // The identifier (in the UI) of this object
00023   var $identifier = '';
00024   var $argument = NULL;
00025   var $keyword = '';
00026 
00027   function panels_context($type = 'none', $data = NULL) {
00028     $this->type  = $type;
00029     $this->data  = $data;
00030     $this->title = t('Unknown context');
00031   }
00032 
00033   function is_type($type) {
00034     if ($type == 'any' || $this->type == 'any') {
00035       return TRUE;
00036     }
00037 
00038     $a = is_array($type) ? $type : array($type);
00039     $b = is_array($this->type) ? $this->type : array($this->type);
00040     return (bool) array_intersect($a, $b);
00041   }
00042 
00043   function get_argument() {
00044     return $this->argument;
00045   }
00046 
00047   function get_keyword() {
00048     return $this->keyword;
00049   }
00050 
00051   function get_identifier() {
00052     return $this->identifier;
00053   }
00054 
00055   function get_title() {
00056     return $this->title;
00057   }
00058 
00059   function get_page_title() {
00060     return $this->page_title;
00061   }
00062 }
00063 
00064 /**
00065  * This is used to explain to Panels what context is required.
00066  */
00067 class panels_required_context {
00068   var $keywords = '';
00069 
00070   function panels_required_context() {
00071     $args = func_get_args();
00072     $this->title = array_shift($args);
00073     if (count($args) == 1) {
00074       $args = array_shift($args);
00075     }
00076     $this->keywords = $args;
00077   }
00078 
00079   function filter($contexts) {
00080     $result = array();
00081 
00082     // See which of these contexts are valid
00083     foreach ($contexts as $cid => $context) {
00084       if ($context->is_type($this->keywords)) {
00085         $result[$cid] = $context;
00086       }
00087     }
00088 
00089     return $result;
00090   }
00091 
00092   function select($contexts, $context) {
00093     if (empty($context) || empty($contexts[$context])) {
00094       return FALSE;
00095     }
00096     return $contexts[$context];
00097   }
00098 }
00099 
00100 class panels_optional_context extends panels_required_context {
00101   function panels_optional_context() {
00102     $args = func_get_args();
00103     call_user_func_array(array($this, 'panels_required_context'), $args);
00104   }
00105 
00106   /**
00107    * Add the 'empty' context which is possible for optional
00108    */
00109   function add_empty(&$contexts) {
00110     $context = new panels_context('any');
00111     $context->title      = t('No context');
00112     $context->identifier = t('No context');
00113     $contexts = array_merge(array('empty' => $context), $contexts);
00114   }
00115 
00116   function filter($contexts) {
00117     $this->add_empty($contexts);
00118     return parent::filter($contexts);
00119   }
00120 
00121   function select($contexts, $context) {
00122     $this->add_empty($contexts);
00123     if (empty($context)) {
00124       return $contexts['empty'];
00125     }
00126 
00127     $result = parent::select($contexts, $context);
00128 
00129     // Don't flip out if it can't find the context; this is optional, put
00130     // in an empty.
00131     if ($result == FALSE) {
00132       $result = $contexts['empty'];
00133     }
00134     return $result;
00135   }
00136 }
00137 
00138 /**
00139  * Master pane access function; combines all the relevant parameters that
00140  * natively used by the Panels API to determine a pane's access. Called from
00141  * panels_render_panes().
00142  *
00143  * @param $pane
00144  *   The pane object to test for access.
00145  * @param $display
00146  *   The display object containing the pane object to be tested.
00147  */
00148 function panels_pane_access($pane, $display) {
00149   global $user;
00150 
00151   // Administrator privileges
00152   if (user_access('view all pane', $user)) {
00153     return TRUE;
00154   }
00155 
00156   $role_access = _panels_pane_access_role($pane, $user);
00157   $type = panels_get_content_type($pane->type);
00158 
00159   if (!$visibility_check = panels_plugin_get_function('content_types', $type, 'visibility check')) {
00160     return $role_access;
00161   }
00162   // Call the content type's custom-defined visibility rendering check.
00163   // Pass as much possibly relevant data as possible.
00164   $visibility_access = $visibility_check($pane, $display, $user);
00165   // Content type marked both access modes to be ANDed together.
00166   if (!empty($type['roles and visibility'])) {
00167     return ($visibility_access === TRUE && $role_access === TRUE) ? TRUE : FALSE;
00168   }
00169   // Err on the safe side: if EVERYTHING else has failed, then don't render the pane.
00170   return isset($visibility_access) ? $visibility_access : FALSE;
00171 }
00172 
00173 /**
00174  * Determine role-based access to a panel pane for the current user
00175  *
00176  * @param object $pane
00177  *  The pane object to test.
00178  * @param object $account
00179  *  The current $user object.
00180  *
00181  * @return bool $role_access
00182  *  The boolean result of the roles-based segment of the Panels access system.
00183  */
00184 function _panels_pane_access_role($pane, $account) {
00185   // All views with an empty access setting are available to all roles.
00186   if (!$pane->access || !is_array($pane->access)) {
00187     return TRUE;
00188   }
00189 
00190   // Otherwise, check roles
00191   static $roles = array();
00192   if (!isset($roles[$account->uid])) {
00193     $roles[$account->uid] = array_keys($account->roles);
00194     $roles[$account->uid][] = $account->uid ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID;
00195   }
00196 
00197   return array_intersect($pane->access, $roles[$account->uid]) ? TRUE : FALSE;
00198 }
00199 
00200 /**
00201  * Get the content from a given content type.
00202  *
00203  * @param $type
00204  *   The content type. May be the name or an already loaded content type object.
00205  * @param $conf
00206  *   The configuration for the content type.
00207  * @param $args
00208  *   The arguments to the content type.
00209  * @param $context
00210  *   The panels_context object.
00211  * @Param $incoming_content
00212  *   Any incoming content, if this display is a wrapper.
00213  */
00214 function panels_ct_get_content($type, $conf, $args, $context, $incoming_content) {
00215   if ($function = panels_plugin_get_function('content_types', $type, 'render callback')) {
00216     $content = $function($conf, $args, $context, $incoming_content);
00217     if (empty($content->title) && !empty($content->subject)) {
00218       $content->title = $content->subject;
00219     }
00220 
00221     if (!empty($content->title) && empty($content->subject)) {
00222       $content->subject = $content->title;
00223     }
00224 
00225     return $content;
00226   }
00227 }
00228 
00229 /**
00230  * Get the title from a given content type.
00231  *
00232  * @param $type
00233  *   The content type. May be the name or an already loaded content type object.
00234  * @param $conf
00235  *   The configuration for the content type.
00236  * @param $context
00237  *   The panels_context object.
00238  * @param $incoming_content
00239  *   Any incoming content, if this display is a wrapper.
00240  */
00241 function panels_ct_get_title($type, $conf, $context = NULL, $incoming_content = NULL) {
00242   if ($function = panels_plugin_get_function('content_types', $type, 'title callback')) {
00243     return $function($conf, $context, $incoming_content);
00244   }
00245   return t('Deleted/missing content type @type', array('@type' => $type));
00246 }
00247 
00248 /**
00249  * Add the default FAPI elements to the content type configuration form
00250  */
00251 function panels_ct_conf_form($ct_data, $contexts, $conf) {
00252   list($subtype, $content_type) = array($ct_data['subtype'], $ct_data['type']);
00253 
00254   if (!empty($subtype['required context']) && is_array($contexts)) {
00255     $form['context'] = panels_context_selector($contexts, $subtype['required context'], isset($conf['context']) ? $conf['context'] : array());
00256   }
00257   elseif (!empty($subtype['optional context']) && is_array($contexts)) {
00258     $form['context'] = panels_context_selector($contexts, $subtype['optional context'], isset($conf['context']) ? $conf['context'] : array());
00259   }
00260 
00261   $style_options = array('default' => t('Default'));
00262   foreach (panels_get_styles() as $name => $properties) {
00263     if (empty($properties['hidden']) && (!empty($properties['render pane']))) {
00264       $style_options[$name] = $properties['title'];
00265     }
00266   }
00267 
00268   asort($style_options);
00269 
00270   if (empty($conf['style'])) {
00271     $conf['style'] = 'default';
00272   }
00273 
00274   if ($style_options) {
00275     $form['style'] = array(
00276       '#type' => 'select',
00277       '#title' => t('Pane style'),
00278       '#default_value' => $conf['style'],
00279       '#options' => $style_options,
00280     );
00281   }
00282 
00283   // Unless we're not allowed to overide the title on this content type, add this
00284   // gadget to all panes.
00285   if (empty($content_type['no title override'])) {
00286     $form['aligner_start'] = array(
00287       '#value' => '<div class="option-text-aligner">',
00288     );
00289     $form['override_title'] = array(
00290       '#type' => 'checkbox',
00291       '#default_value' => isset($conf['override_title']) ? $conf['override_title'] : '',
00292       '#title' => t('Override title'),
00293       '#id' => 'override-title-checkbox',
00294     );
00295     $form['override_title_text'] = array(
00296       '#type' => 'textfield',
00297       '#default_value' => isset($conf['override_title_text']) ? $conf['override_title_text'] : '',
00298       '#size' => 35,
00299       '#id' => 'override-title-textfield',
00300     );
00301     $form['aligner_stop'] = array(
00302       '#value' => '</div><div style="clear: both; padding: 0; margin: 0"></div>',
00303     );
00304     $form['override_title_markup'] = array(
00305       '#prefix' => '<div class="description">',
00306       '#suffix' => '</div>',
00307       '#value' => t('You may use %keywords from contexts, as well as %title to contain the original title.'),
00308     );
00309   }
00310 
00311   // Add CSS class and ID gadgets to all panes if advanced pane settings is set.
00312   if (user_access('administer advanced pane settings')) {
00313     $form['css_id'] = array(
00314       '#type' => 'textfield',
00315       '#default_value' => isset($conf['css_id']) ? $conf['css_id'] : '',
00316       '#title' => t('CSS ID'),
00317       '#description' => t('CSS ID to apply to this content. This may be blank.'),
00318       '#weight' => 2,
00319       '#size' => 15,
00320     );
00321     $form['css_class'] = array(
00322       '#type' => 'textfield',
00323       '#default_value' => isset($conf['css_class']) ? $conf['css_class'] : '',
00324       '#title' => t('CSS class'),
00325       '#description' => t('CSS class to apply to this content. This may be blank.'),
00326       '#weight' => 2,
00327       '#size' => 15,
00328     );
00329   }
00330 
00331   return $form;
00332 }
00333 
00334 /**
00335  * Call any content type-defined add/edit callbacks so that additions
00336  * to $form['configuration'] can be made.
00337  *
00338  * @see panels_content_config_form()
00339  *
00340  * @param object $pane
00341  *   The $pane object currently being edited.
00342  * @param $contexts
00343  *   A list of possible contexts.
00344  * @param $parents
00345  *   The #parents to be used on the form, because some form gadgets need to
00346  *   know where they live.
00347  * @param string $op
00348  *  Either 'add' or 'edit' depending on the operation being performed.
00349  * @param mixed $content_type
00350  *  This variable should only be passed if the calling function already has access to the
00351  *  relevant content_type data and wants to save a little on performance. If so, then the
00352  *  fully-loaded content type plugin declaration array should be passed.
00353  */
00354 function panels_ct_pane_config_form($pane, $contexts, $parents, $op, $content_type = 'content_types') {
00355   if ($function = panels_plugin_get_function($content_type, $pane->type, "$op callback")) {
00356     return $function($pane->subtype, $parents, $pane->configuration);
00357   }
00358 }
00359 
00360 /**
00361  * Call any add/edit validators defined by the content type.
00362  *
00363  * @see panels_content_config_form_validate()
00364  *
00365  * @param $type
00366  *   The content type. May be the name or an already loaded content type object.
00367  * @param $form
00368  *   The actual Forms API form that is being validated.
00369  * @param $form_values
00370  *   The actual Forms API values being validated.
00371  * @param string $op
00372  *  Either 'add' or 'edit' depending on the operation being performed.
00373  */
00374 function panels_ct_pane_validate_form($content_type, $form, $form_values, $op) {
00375   if ($function = panels_plugin_get_function('content_types', $content_type, "$op validate callback")) {
00376     return $function($form, $form_values);
00377   }
00378 }
00379 
00380 /**
00381  * Call any add/edit submit handlers defined by the content type.
00382  *
00383  * @param string $content_type
00384  *  A string value containing the name of the content type.
00385  * @param $form_values
00386  *  The $form_values['configuration'] sub-array generated by FAPI for the
00387  *  overall ct add/edit submit handler.
00388  * @param string $op
00389  *  Either 'add' or 'edit' depending on the operation being performed.
00390  */
00391 function panels_ct_pane_submit_form($content_type, $form_values, $op) {
00392   if ($function = panels_plugin_get_function('content_types', $content_type, "$op submit callback")) {
00393     return $function($form_values);
00394   }
00395 }
00396 
00397 /**
00398  * Get all of the individual types provided by a given content types. This
00399  * would be all of the blocks for the block type, or all of the views for
00400  * the view type.
00401  *
00402  * @param $type
00403  *   The content type to load.
00404  */
00405 function panels_ct_get_types($type) {
00406   if (is_array($type)) {
00407     $content_type = $type;
00408   }
00409   else {
00410     $content_type = panels_get_content_type($type);
00411   }
00412 
00413   $function = $content_type['content_types'];
00414   if (is_array($function)) {
00415     return (array) $function;
00416   }
00417 
00418   if (function_exists($function)) {
00419     return (array) $function();
00420   }
00421   return array();
00422 }
00423 
00424 /**
00425  * Get a list of panels available in the layout.
00426  */
00427 function panels_get_panels($layout, $display) {
00428   if (!empty($layout['panels function']) && function_exists($layout['panels function'])) {
00429     return $layout['panels function']($display, $display->layout_settings);
00430   }
00431   if (!empty($layout['panels'])) {
00432     return $layout['panels'];
00433   }
00434   return array();
00435 }
00436 
00437 /**
00438  * Get an array of all available content types that can be fed into the
00439  * display editor for the add content list.
00440  *
00441  * @param $context
00442  *   If a context is provided, content that requires that context can apepar.
00443  * @param $has_content
00444  *   Whether or not the display will have incoming content
00445  * @param $allowed_types
00446  *   An array of allowed content types (pane types) keyed by content_type . '-' . sub_type
00447  * @param $default_types
00448  *   A default allowed/denied status for content that isn't known about
00449  */
00450 function panels_get_available_content_types($contexts = NULL, $has_content = FALSE, $allowed_types = NULL, $default_types = NULL) {
00451   $content_types = panels_get_content_types();
00452   $available = array();
00453 
00454   foreach ($content_types as $id => $type) {
00455     foreach (panels_ct_get_types($type) as $cid => $cinfo) {
00456       // exclude items that require content if we're saying we don't
00457       // provide it.
00458       if (!empty($cinfo['requires content']) && !$has_content) {
00459         continue;
00460       }
00461 
00462       // Check to see if the content type can be used in this context.
00463       if (!empty($cinfo['required context'])) {
00464         if (!panels_context_filter($contexts, $cinfo['required context'])) {
00465           continue;
00466         }
00467       }
00468 
00469       // Check to see if the passed-in allowed types allows this content.
00470       if ($allowed_types) {
00471         $key = $id . '-' . $cid;
00472         if (!isset($allowed_types[$key])) {
00473           $allowed_types[$key] = isset($default_types[$id]) ? $default_types[$id] : $default_types['other'];
00474         }
00475         if (!$allowed_types[$key]) {
00476           continue;
00477         }
00478       }
00479 
00480       // If we made it through all the tests, then we can use this content.
00481       $available[$id][$cid] = $cinfo;
00482     }
00483   }
00484   return $available;
00485 }
00486 
00487 /**
00488  * Get an array of all content types that can be fed into the
00489  * display editor for the add content list, regardless of
00490  * availability.
00491  *
00492  */
00493 function panels_get_all_content_types() {
00494   $content_types = panels_get_content_types();
00495   $available = array();
00496 
00497   foreach ($content_types as $id => $type) {
00498     foreach (panels_ct_get_types($type) as $cid => $cinfo) {
00499       // If we made it through all the tests, then we can use this content.
00500       $available[$id][$cid] = $cinfo;
00501     }
00502   }
00503   return $available;
00504 }
00505 
00506 // ------------------------------------------------------------------
00507 // Functions to provide information about a panel or part of a panel.
00508 
00509 /**
00510  * Get the content from a given pane.
00511  *
00512  * @ingroup HookInvokers
00513  *
00514  * @param $pane
00515  *   The pane to retrieve content from.
00516  * @param $args
00517  *   The arguments sent to the display.
00518  * @param $context
00519  *   The panels context.
00520  * @param $incoming_content
00521  *   Any incoming content if this display is a wrapper.
00522  */
00523 function panels_get_pane_content($display, $pane, $args = array(), $context = NULL, $incoming_content = '') {
00524   if (!$context) {
00525     $context = new panels_context;
00526   }
00527   // FIXME misplaced bang?
00528   if (!$incoming_content === '') {
00529     $incoming_content = t('Incoming content will be displayed here.');
00530   }
00531 
00532   $content = FALSE;
00533   $caching = !empty($pane->cache['method']) ? TRUE : FALSE;
00534   if ($caching && ($cache = panels_get_cached_content($display, $args, $context, $pane))) {
00535     $content = $cache->content;
00536   }
00537   else {
00538     $content = panels_ct_get_content($pane->type, $pane->configuration, $args, $context, $incoming_content);
00539     foreach (module_implements('panels_pane_content_alter') as $module) {
00540       // TODO This makes the third hook invocation on the render path. How badly is this hindering performance?
00541       $function = $module . '_panels_pane_content_alter';
00542       $function($content, $pane, $args, $context);
00543     }
00544     if ($caching) {
00545       $cache = new panels_cache_object();
00546       $cache->set_content($content);
00547       panels_set_cached_content($cache, $display, $args, $context, $pane);
00548     }
00549   }
00550 
00551   return $content;
00552 }
00553 
00554 /**
00555  * Get cached content for a given display and possibly pane.
00556  *
00557  * @return
00558  *   The cached content, or FALSE to indicate no cached content exists.
00559  */
00560 function panels_get_cached_content($display, $args, $context, $pane = NULL) {
00561   $method = $pane ? $pane->cache['method'] : $display->cache['method'];
00562   $function = panels_plugin_get_function('cache', $method, 'cache get');
00563 
00564   if (!$function) {
00565     return FALSE;
00566   }
00567 
00568   $conf = $pane ? $pane->cache['settings'] : $display->cache['settings'];
00569   $cache = $function($conf, $display, $args, $context, $pane);
00570   if (empty($cache)) {
00571     return FALSE;
00572   }
00573 
00574   // restore it.
00575   $cache->restore();
00576   return $cache;
00577 }
00578 
00579 /**
00580  * Store cached content for a given display and possibly pane.
00581  */
00582 function panels_set_cached_content($cache, $display, $args, $context, $pane = NULL) {
00583   $method = $pane ? $pane->cache['method'] : $display->cache['method'];
00584   $function = panels_plugin_get_function('cache', $method, 'cache set');
00585 
00586   if (!$function) {
00587     return FALSE;
00588   }
00589 
00590   $conf = $pane ? $pane->cache['settings'] : $display->cache['settings'];
00591 
00592   // snapshot it.
00593   $cache->cache();
00594   return $function($conf, $cache, $display, $args, $context, $pane);
00595 }
00596 
00597 /**
00598  * Clear all cached content for a display.
00599  */
00600 function panels_clear_cached_content($display) {
00601   // Figure out every method we might be using to cache content in this display:
00602   $methods = array();
00603   if (!empty($display->cache['method'])) {
00604     $methods[$display->cache['method']] = TRUE;
00605   }
00606 
00607   foreach ($display->content as $pane) {
00608     if (!empty($pane->cache['method'])) {
00609       $methods[$pane->cache['method']] = TRUE;
00610     }
00611   }
00612 
00613   foreach (array_keys($methods) as $method) {
00614     $function = panels_plugin_get_function('cache', $method, 'cache clear');
00615     if ($function) {
00616       $function($display);
00617     }
00618   }
00619 }
00620 
00621 /**
00622  * An object to hold caching information while it is happening.
00623  */
00624 class panels_cache_object {
00625   var $content = '';
00626   var $head = NULL;
00627   var $css = NULL;
00628   var $js = NULL;
00629   var $ready = FALSE;
00630 
00631   /**
00632    * When constructed, take a snapshot of our existing out of band data.
00633    */
00634   function panels_cache_object() {
00635     $this->head = drupal_set_html_head();
00636     $this->css = drupal_add_css();
00637 
00638     foreach (array('header', 'footer') as $scope) {
00639       $this->js[$scope] = drupal_add_js(NULL, NULL, $scope);
00640     }
00641   }
00642 
00643   /**
00644    * Add content to the cache. This assumes a pure stream;
00645    * use set_content() if it's something else.
00646    */
00647   function add_content($content) {
00648     $this->content .= $content;
00649   }
00650 
00651   function set_content($content) {
00652     $this->content = $content;
00653   }
00654 
00655   /**
00656    * Set the object for storing. This overwrites.
00657    */
00658   function cache() {
00659     if ($this->ready) {
00660       return;
00661     }
00662 
00663     $this->ready = TRUE;
00664 
00665     // Simple replacement for head
00666     $this->head = str_replace($this->head, '', drupal_set_html_head());
00667 
00668     // Slightly less simple for CSS:
00669     $css = drupal_add_css();
00670     $start = $this->css;
00671     $this->css = array();
00672 
00673     foreach ($css as $media => $medias) {
00674       foreach ($medias as $type => $types) {
00675         foreach ($types as $path => $preprocess) {
00676           if (!isset($start[$media][$type][$path])) {
00677             $this->css[] = array($path, $type, $media, $preprocess);
00678           }
00679         }
00680       }
00681     }
00682 
00683     $js = array();
00684     // A little less simple for js
00685     foreach (array('header', 'footer') as $scope) {
00686       $js[$scope] = drupal_add_js(NULL, NULL, $scope);
00687     }
00688 
00689     $start = $this->js;
00690     $this->js = array();
00691 
00692     foreach ($js as $scope => $scopes) {
00693       foreach ($scopes as $type => $types) {
00694         foreach ($types as $id => $info) {
00695           if (!isset($start[$scope][$type][$id])) {
00696             switch ($type) {
00697               case 'setting':
00698                 $this->js[] = array($info, $type, $scope);
00699                 break;
00700 
00701               case 'inline':
00702                 $this->js[] = array($info['code'], $type, $scope, $info['defer']);
00703                 break;
00704 
00705               default:
00706                 $this->js[] = array($id, $type, $scope, $info['defer'], $info['cache']);
00707             }
00708           }
00709         }
00710       }
00711     }
00712   }
00713 
00714   /**
00715    * Restore out of band data saved to cache.
00716    */
00717   function restore() {
00718     if (!empty($this->head)) {
00719       drupal_set_html_head($this->head);
00720     }
00721     if (!empty($this->css)) {
00722       foreach ($this->css as $args) {
00723         call_user_func_array('drupal_add_css', $args);
00724       }
00725     }
00726     if (!empty($this->js)) {
00727       foreach ($this->js as $args) {
00728         call_user_func_array('drupal_add_js', $args);
00729       }
00730     }
00731   }
00732 }
00733 
00734 /**
00735  * Get the title of a pane.
00736  *
00737  * @param $pane
00738  *   The $pane object.
00739  */
00740 function panels_get_pane_title(&$pane, $context = array(), $incoming_content = NULL) {
00741   if (empty($pane->context)) {
00742     $pane->context = panels_pane_select_context($pane, $context);
00743     if ($pane->context === FALSE) {
00744       return t('Does not meet context requirements');
00745     }
00746   }
00747   return panels_ct_get_title($pane->type, $pane->configuration, $pane->context, $incoming_content);
00748 }
00749 
00750 // ---------------------------------------------------------------------------
00751 // panels argument helpers
00752 
00753 /**
00754  * Get a context from an argument
00755  */
00756 function panels_argument_get_context($argument, $arg, $empty = FALSE) {
00757   if ($function = panels_plugin_get_function('arguments', $argument['name'], 'context')) {
00758     $context = $function($arg, $argument['argument_settings'], $empty);
00759 
00760     if ($context) {
00761       $context->identifier = $argument['identifier'];
00762       $context->page_title = $argument['title'];
00763       $context->keyword    = $argument['keyword'];
00764       return $context;
00765     }
00766   }
00767 }
00768 
00769 /**
00770  * Pick which display an argument wants to use
00771  */
00772 function panels_argument_choose_display($type, $conf, $context) {
00773   if ($function = panels_plugin_get_function('arguments', $type, 'choose display')) {
00774     return $function($conf, $context);
00775   }
00776 }
00777 
00778 /**
00779  * Determine a unique context ID for an argument
00780  */
00781 function panels_argument_context_id($argument) {
00782   return "argument_$argument[name]_$argument[id]";
00783 }
00784 
00785 /**
00786  * Retrieve a list of empty contexts for all arguments
00787  */
00788 function panels_argument_get_contexts($arguments) {
00789   $contexts = array();
00790   foreach ($arguments as $argument) {
00791     $context = panels_argument_get_context($argument, NULL, true);
00792     if ($context) {
00793       $contexts[panels_argument_context_id($argument)] = $context;
00794     }
00795   }
00796   return $contexts;
00797 }
00798 
00799 /**
00800  * Load the contexts for a given panel.
00801  *
00802  * @param $arguments
00803  *   The array of argument definitions
00804  * @param &$contexts
00805  *   The array of existing contexts.
00806  * @param $args
00807  *   The arguments to load
00808  *
00809  * @return
00810  *   FALSE if an argument wants to 404.
00811  */
00812 function panels_argument_load_contexts($arguments, &$contexts, $args) {
00813   foreach ($arguments as $argument) {
00814     // pull the argument off the list.
00815     $arg = array_shift($args);
00816     $id = panels_argument_context_id($argument);
00817 
00818     // For % arguments embedded in the URL, our context is already loaded.
00819     // There is no need to go and load it again.
00820     if (empty($contexts[$id])) {
00821       if ($context = panels_argument_get_context($argument, $arg)) {
00822         $contexts[$id] = $context;
00823       }
00824     }
00825     else {
00826       $context = $contexts[$id];
00827     }
00828 
00829     if ((empty($context) || empty($context->data)) && $argument['default'] == '404') {
00830       return FALSE;
00831     }
00832   }
00833   return TRUE;
00834 }
00835 
00836 /**
00837  * Choose a display based upon arguments and loaded contexts.
00838  *
00839  * @param $arguments
00840  *   The array of argument definitions
00841  * @param $contexts
00842  *   The array of existing contexts.
00843  *
00844  * @return
00845  *   The identification of the display to use
00846  */
00847 function panels_argument_get_display($arguments, $contexts) {
00848   $display_candidate = NULL;
00849   foreach ($arguments as $i => $argument) {
00850     $id = panels_argument_context_id($argument);
00851     if (!empty($contexts[$id]) && !empty($contexts[$id]->data)) {
00852       $context = $contexts[$id];
00853       $d = panels_argument_choose_display($argument['name'], $argument['argument_settings'], $context);
00854       if ($d) {
00855         $display_candidate = "argument_$i" . '-' . $d;
00856       }
00857     }
00858   }
00859 
00860   return $display_candidate;
00861 }
00862 
00863 // ---------------------------------------------------------------------------
00864 // panels relationship helpers
00865 
00866 /**
00867  * Fetch all relevant relationships
00868  *
00869  * @param $contexts
00870  *   An array of contexts used to figure out which relationships are relevant.
00871  *
00872  * @return
00873  *   An array of relationship keys that are relevant for the given set of
00874  * arguments.
00875  */
00876 function panels_get_relevant_relationships($contexts) {
00877   $relevant = array();
00878   $relationships = panels_get_relationships();
00879 
00880   // Go through each relationship
00881   foreach ($relationships as $rid => $relationship) {
00882     // For each relationship, see if there is a context that satisfies it.
00883     if (panels_context_filter($contexts, $relationship['required context'])) {
00884       $relevant[$rid] = $relationship['title'];
00885     }
00886   }
00887 
00888   return $relevant;
00889 }
00890 
00891 /**
00892  * Fetch all active relationships
00893  *
00894  * @param $relationships
00895  *   An keyed array of relationship data including:
00896  *   - name: name of relationship
00897  *   - context: context id relationship belongs to.
00898  *
00899  * @param $contexts
00900  *   A keyed array of contexts used to figure out which relationships
00901  *   are relevant. New contexts will be added to this.
00902  *
00903  */
00904 function panels_relationship_get_contexts($relationships, &$contexts) {
00905   $return = array();
00906 
00907   foreach ($relationships as $rdata) {
00908     if (empty($contexts[$rdata['context']])) {
00909       continue;
00910     }
00911     $relationship = panels_get_relationship($rdata['name']);
00912     // If the relationship can't be found or its context can't be found,
00913     // ignore.
00914     if (!$relationship) {
00915       continue;
00916     }
00917 
00918     $cid = panels_relationship_context_id($rdata);
00919     if ($context = panels_relationship_get_context($rdata, $contexts[$rdata['context']])) {
00920       $contexts[$cid] = $context;
00921     }
00922   }
00923 }
00924 
00925 /**
00926  * Determine a unique context ID for an argument
00927  */
00928 function panels_relationship_context_id($relationship) {
00929   return "relationship_$relationship[name]_$relationship[id]";
00930 }
00931 
00932 /**
00933  * Fetch a context from a relationship, given the context input.
00934  */
00935 function panels_relationship_get_context($relationship, $arg) {
00936   if ($function = panels_plugin_get_function('relationships', $relationship['name'], 'context')) {
00937     $context = $function($arg, $relationship['relationship_settings']);
00938     if ($context) {
00939       $context->identifier = $relationship['identifier'];
00940       $context->page_title = $relationship['title'];
00941       $context->keyword    = $relationship['keyword'];
00942       return $context;
00943     }
00944   }
00945 }
00946 
00947 // ---------------------------------------------------------------------------
00948 // panels context helpers
00949 
00950 /**
00951  * Return a keyed array of context that match the given 'required context'
00952  * filters.
00953  *
00954  * @param $contexts
00955  *   A keyed array of all available contexts.
00956  * @param $required
00957  *   The required context string or array.
00958  *
00959  * @return
00960  *   A keyed array of contexts.
00961  */
00962 function panels_context_filter($contexts, $required) {
00963   if (is_array($required)) {
00964     $result = array();
00965     foreach ($required as $r) {
00966       $result = array_merge($result, _panels_context_filter($contexts, $r));
00967     }
00968     return $result;
00969   }
00970 
00971   return _panels_context_filter($contexts, $required);
00972 }
00973 
00974 function _panels_context_filter($contexts, $required) {
00975   // TODO: Multiples
00976   $result = array();
00977 
00978   if (is_object($required)) {
00979     $result = $required->filter($contexts);
00980   }
00981 
00982   return $result;
00983 }
00984 
00985 /**
00986  * Create a select box to choose possible contexts. This only creates a
00987  * selector if there is actually a choice.
00988  *
00989  * @param $contexts
00990  *   A keyed array of all available contexts.
00991  * @param $required
00992  *   The required context string or array.
00993  *
00994  * @return
00995  *   A form element, or NULL if there are no contexts that satisfy the
00996  *   requirements.
00997  */
00998 function panels_context_selector($contexts, $required, $default) {
00999   if (is_array($required)) {
01000     $result = array();
01001     $count = 1;
01002     foreach ($required as $id => $r) {
01003       $result[] = _panels_context_selector($contexts, $r, $default[$id], $count++);
01004     }
01005     return $result;
01006   }
01007 
01008   return _panels_context_selector($contexts, $required, $default);
01009 }
01010 
01011 function _panels_context_selector($contexts, $required, $default, $num = 0) {
01012   $filtered = panels_context_filter($contexts, $required);
01013   $count = count($filtered);
01014 
01015   $form = array();
01016 
01017   if ($count == 1) {
01018     $keys = array_keys($filtered);
01019     return array(
01020       '#type' => 'value',
01021       '#value' => $keys[0],
01022     );
01023   }
01024 
01025   if ($count > 1) {
01026     // If there's more than one to choose from, create a select widget.
01027     foreach ($filtered as $cid => $context) {
01028       $options[$cid] = $context->get_identifier();
01029     }
01030     if (!empty($required->title)) {
01031       $title = $required->title;
01032     }
01033     else {
01034       $title = $num ? t('Context %count', array('%count' => $num)) : t('Context');
01035     }
01036 
01037     return array(
01038       '#type' => 'select',
01039       '#options' => $options,
01040       '#title' => $title,
01041       '#description' => t('Multiple contexts are valid for this pane; one must be chosen.'),
01042       '#default_value' => $default,
01043     );
01044   }
01045 }
01046 
01047 /**
01048  * Choose a context based upon the selection made via panels_context_filter
01049  *
01050  * @param $contexts
01051  *   A keyed array of all available contexts
01052  * @param $required
01053  *   The required context object provided by the plugin
01054  * @param $context
01055  *   The selection made using panels_context_selector
01056  */
01057 function panels_context_select($contexts, $required, $context) {
01058   if (is_array($required)) {
01059     $result = array();
01060     foreach ($required as $id => $r) {
01061       if (($result[] = _panels_context_select($contexts, $r, $context[$id])) == FALSE) {
01062         return FALSE;
01063       }
01064     }
01065     return $result;
01066   }
01067 
01068   return _panels_context_select($contexts, $required, $context);
01069 }
01070 
01071 function _panels_context_select($contexts, $required, $context) {
01072   if (!is_object($required)) {
01073     return FALSE;
01074   }
01075 
01076   return $required->select($contexts, $context);
01077 }
01078 
01079 /**
01080  * Create a new context.
01081  *
01082  * @param $type
01083  *   The type of context to create; this loads a plugin.
01084  * @param $data
01085  *   The data to put into the context.
01086  * @param $conf
01087  *   A configuration structure if this context was created via UI.
01088  *
01089  * @return
01090  *   A $context or NULL if one could not be created.
01091  */
01092 function panels_context_create($type, $data = NULL, $conf = FALSE) {
01093   if ($function = panels_plugin_get_function('contexts', $type, 'context')) {
01094     return $function(FALSE, $data, $conf);
01095   }
01096 }
01097 
01098 function panels_context_create_empty($type, $conf = FALSE) {
01099   if ($function = panels_plugin_get_function('contexts', $type, 'context')) {
01100     return $function(TRUE, NULL, $conf);
01101   }
01102 }
01103 
01104 /**
01105  * Fetch keywords for use in string substitutions.
01106  *
01107  * @param $contexts
01108  *   An array of contexts.
01109  *
01110  * @return
01111  *   An array of keyword substitutions suitable for strtr()
01112  */
01113 function panels_context_get_keywords($contexts) {
01114   $keywords = array();
01115   foreach ($contexts as $id => $context) {
01116     if ($keyword = $context->get_keyword()) {
01117       $keywords["%$keyword"] = $context->get_title();
01118     }
01119   }
01120   return $keywords;
01121 }
01122 
01123 /**
01124  * Determine a unique context ID for a context
01125  *
01126  * @todo can probably combine the various versions of this.
01127  */
01128 function panels_context_context_id($context, $type = 'context') {
01129   return $type . "_$context[name]_$context[id]";
01130 }
01131 
01132 /**
01133  * Get a context from a context object.
01134  */
01135 function panels_context_get_context($context, $type = 'context') {
01136   if ($function = panels_plugin_get_function('contexts', $context['name'], 'context')) {
01137     $return = $function($type == 'requiredcontext', $context['context_settings'], TRUE);
01138     if ($return) {
01139       $return->identifier = $context['identifier'];
01140       $return->page_title = $context['title'];
01141       $return->keyword    = $context['keyword'];
01142       return $return;
01143     }
01144   }
01145 }
01146 
01147 /**
01148  * Retrieve a list of empty contexts for all contexts
01149  */
01150 function panels_context_get_contexts($contexts, $type = 'context') {
01151   $return = array();
01152   foreach ($contexts as $context) {
01153     $ctext = panels_context_get_context($context, $type);
01154     if ($ctext) {
01155       $return[panels_context_context_id($context, $type)] = $ctext;
01156     }
01157   }
01158   return $return;
01159 }
01160 
01161 /**
01162  * Get a group of empty contexts for the object; this assumes all the
01163  * standard context types, and doesn't punish you if they aren't
01164  * available.
01165  */
01166 function panels_context_load_contexts($object, $placeholders = TRUE, $contexts = array()) {
01167   if ($placeholders) {
01168     // This will load empty contexts as placeholders for arguments that come
01169     // from external sources. If this isn't set, it's assumed these context
01170     // will already have been matched up and loaded.
01171     if (!empty($object->requiredcontexts) && is_array($object->requiredcontexts)) {
01172       $contexts += panels_context_get_contexts($object->requiredcontexts, 'requiredcontext');
01173     }
01174 
01175     if (!empty($object->arguments) && is_array($object->arguments)) {
01176       $contexts += panels_argument_get_contexts($object->arguments);
01177     }
01178   }
01179 
01180   if (!empty($object->contexts) && is_array($object->contexts)) {
01181     $contexts += panels_context_get_contexts($object->contexts);
01182   }
01183 
01184   // add contexts from relationships
01185   if (!empty($object->relationships) && is_array($object->relationships)) {
01186     panels_relationship_get_contexts($object->relationships, $contexts);
01187   }
01188 
01189   return $contexts;
01190 }
01191 
01192 /**
01193  * Match up external contexts to our required contexts. It shouldn't be
01194  * possible to get here without the contexts already lining up properly.
01195  */
01196 function panels_context_match_required_contexts($required, $contexts) {
01197   $return = array();
01198   if (!is_array($required)) {
01199     return $return;
01200   }
01201 
01202   foreach ($required as $r) {
01203     $return[panels_context_context_id($r, 'requiredcontext')] = array_shift($contexts);
01204   }
01205 
01206   return $return;
01207 }
01208 
01209 /**
01210  * Return the first context with a form id from a list of contexts.
01211  */
01212 function panels_context_get_form($contexts) {
01213   foreach ($contexts as $context) {
01214     if (!empty($context->form_id)) {
01215       return $context;
01216     }
01217   }
01218 }
01219 
01220 /**
01221  * Select a context for a pane.
01222  *
01223  * @param object $pane
01224  *   A fully populated pane.
01225  * @param array $contexts
01226  *   A keyed array of available contexts.
01227  * @param string $context_type
01228  *   Indicates whether a required or optional context is being sought.
01229  *
01230  * @return
01231  *   The matching contexts or NULL if none or necessary, or FALSE if
01232  *   requirements can't be met.
01233  */
01234 function panels_pane_select_context($pane, $contexts, $context_type = 'required context') {
01235   // Identify which of our possible contexts apply.
01236   if (empty($pane->subtype)) {
01237     return;
01238   }
01239 
01240   $content_type = panels_ct_get_types($pane->type);
01241   // If the pane requires a context, fetch it; if no context is returned,
01242   // do not display the pane.
01243   if (empty($content_type[$pane->subtype][$context_type])) {
01244     return $context_type == 'required context' ? panels_pane_select_context($pane, $contexts, 'optional context') : NULL;
01245   }
01246 
01247   $context = panels_context_select($contexts, $content_type[$pane->subtype][$context_type], $pane->configuration['context']);
01248 
01249   return $context;
01250 }
01251 
01252 
01253 // ---------------------------------------------------------------------------
01254 // switcher passthrough
01255 
01256 /**
01257  * Switch one object for another just prior to load.
01258  *
01259  * @param $plugin
01260  *   The name or loaded plugin to delegate switching to.
01261  * @param $type
01262  *   The object type. eg, 'panels_page', 'panels_mini', etc.
01263  * @param $name
01264  *   The name of the object that might be switched.
01265  * @param $candidates
01266  *   A list of possible objects to switch to. The data conforms to
01267  *   what was set in the settings, and is keyed to the panel.
01268  *
01269  * @return
01270  *   The object to switch to. NULL if electing not to switch.
01271  */
01272 function panels_switcher_switch($plugin, $type, $name, $candidates) {
01273   $function = panels_plugin_get_function('switchers', $plugin, 'switch');
01274   if ($function) {
01275     return $function($type, $name, $candidates);
01276   }
01277 }
01278 
01279 /**
01280  * Get a function from a plugin, if it exists.
01281  *
01282  * @param $plugin
01283  *   The type of plugin
01284  * @param $which
01285  *   Either the loaded plugin object (or the same data in array form)
01286  *   or a string with the name of the desired the specific plugin.
01287  * @param $function_name
01288  *   The identifier of the function. For example, 'settings form'.
01289  *
01290  * @return
01291  *   The actual name of the function to call, or NULL if the function
01292  *   does not exist.
01293  */
01294 function panels_plugin_get_function($plugin, $which, $function_name) {
01295   if (is_object($which) || is_array($which)) {
01296     $plugin_data = $which;
01297   }
01298   else {
01299     $hook = "panels_$plugin";
01300     $plugin_data = panels_get_plugins($plugin, $hook, $which);
01301   }
01302 
01303   if (isset($plugin_data[$function_name]) && function_exists($plugin_data[$function_name])) {
01304     return $plugin_data[$function_name];
01305   }
01306 }
01307 
01308 // ---------------------------------------------------------------------------
01309 // panels data loading
01310 
01311 /**
01312  * Load plugins from a directory.
01313  *
01314  * @param $plugin_type
01315  *   The plugin type, as well as the panels directory where the plugin is kept.
01316  *   A list of additional directories to search for relevant plugins is generated by invoking hook_panels_include_directory();
01317  * @param $hook
01318  *   The name of the hook to be invoked.
01319  * @param $file
01320  *   The file to load if we're looking for just one particular plugin.
01321  *
01322  * @return
01323  *   An array of information created for this plugin.
01324  */
01325 function panels_load_includes($plugin_type, $hook, $file = NULL) {
01326   // Load all our plugins.
01327   $directories = panels_get_include_directories($plugin_type);
01328   // $directories['panels'] = panels_get_path($plugin_type);
01329   $file_list = array();
01330   foreach ($directories as $module => $path) {
01331     $file_list[$module] = drupal_system_listing("$file" . '.inc$', $path, 'name', 0);
01332   }
01333   $info = array();
01334   foreach (array_filter($file_list) as $module => $files) {
01335     foreach ($files as $file) {
01336       require_once ('./' . $file->filename);
01337       $result = _panels_process_plugin($module, $module . '_' . $file->name, dirname($file->filename), $hook);
01338       if (is_array($result)) {
01339         $info = array_merge($info, $result);
01340       }
01341     }
01342   }
01343   return $info;
01344 }
01345 
01346 /**
01347  * Invocation of panels_include_directory(), part of the main panels API.
01348  *
01349  * @ingroup MainAPI
01350  * @ingroup HookInvokers
01351  * @see panels_panels_include_directory()
01352  *
01353  * This hook allows other modules to create their own panels .inc files
01354  * according to the same filename and directory schema utilized by Panels
01355  * itself, or some other arbitrary schema defined in implementations of the
01356  * hook. Essentially, instead of having to declare all all callback definitions
01357  * for a given plugin in a single hook implementation specific to that plugin
01358  * calling this hook allows the caller to define a directory where Panels will
01359  * then look for .inc files with callback declarations that conform to the
01360  * naming scheme. The net result is the same, but implementing this hook does
01361  * allow for better organization and flexibility in your .inc files, which is
01362  * particularly preferable if you're implementing a lot of them.
01363  *
01364  * PLEASE NOTE: There are strict naming conventions on implementing this hook;
01365  * failure to follow the conventions will likely cause your plugins not to
01366  * work. Possibly even worse, failure to follow the conventions can result in
01367  * namespace collisions between your module and other modules invoking the
01368  * panels API.
01369  *
01370  * @param string $plugintype
01371  *   The type of Panels plugin being requested. Can be any of the following
01372  *   seven: 'content_types', 'contexts', 'arguments', 'layouts', 'styles',
01373  *   'relationships', 'cache', 'switchers'
01374  *
01375  * @return array $directories
01376  *   Returns an array of include subdirectories to call for the requested
01377  *   plugin type.  Subdirectories should be ONLY the subdirectory of your
01378  *   module where the appropriate types of .inc files reside.
01379  */
01380 function panels_get_include_directories($plugin_type) {
01381   $directories = array();
01382   foreach (module_implements('panels_include_directory') as $module) {
01383     $result = module_invoke($module, 'panels_include_directory', $plugin_type);
01384     if (isset($result) && is_string($result)) {
01385       $directories[$module] = drupal_get_path('module', $module) .'/'. $result;
01386     }
01387   }
01388   return $directories;
01389 }
01390 
01391 /**
01392  * Implementation of hook_panels_include_directory().
01393  *
01394  * @see panels_get_include_directories()
01395  *
01396  * This simple implementation of hook_panels_include_directory() is sufficient
01397  * to mark all seven of the Panels subdirectories corresponding to the different
01398  * plugin types as plugin directories that the Panels engine will search for
01399  * plugins of that type when a request for those plugins are made.
01400  *
01401  * It is important that separate directories be defined for each of the plugin
01402  * types. While failure to separate the plugin directories should not result in
01403  * an error, it will undermine the Panels engine's lazy-loading logic and
01404  * negatively impact memory usage.
01405  *
01406  * Note also that including a conditional on the plugin type so that you only
01407  * define plugins for directories that you have actually populated with plugin
01408  * include files is another small contribution to performance that you can make.
01409  * For example, if you define only content_type and context plugins and don't
01410  * want them at the root level of your module directory, this code would work:
01411  * @code
01412  *  function MYMODULE_panels_include_directory($plugin_type) {
01413  *    if ($plugin_type == 'content_types' || $plugin_type == 'contexts') {
01414  *      return 'panels_inc/' . $plugin_type;
01415  *    }
01416  *  }
01417  * @endcode
01418  *
01419  * @param string $plugin_type
01420  *    The plugin type for which the Panels engine is currently requesting the
01421  *    location of an include directory.
01422  * @return string
01423  *    The location of the include directory for plugin type being requested,
01424  *    relative to the base directory of the module implementing this hook.
01425  */
01426 function panels_panels_include_directory($plugin_type) {
01427   return $plugin_type;
01428 }
01429 
01430 /**
01431  * Load plugin info for the provided hook; this is handled separately from
01432  * plugins from files.
01433  *
01434  * IMPORTANT: The hooks invoked by this function do work, but it is _not_ the
01435  * preferred method, as it is left up to the module invoking the hook to handle
01436  * including separate .inc files with potentially unneeded functions - and there
01437  * is no way for any entity external to the Panels engine to know if that
01438  * inclusion is necessary. Consequently, hook_panels_include_directory() should
01439  * be used unless some aspect of the client's implementation is incompatible
01440  * with that approach.
01441  *
01442  * @see panels_get_include_directories()
01443  *
01444  * @ingroup HookInvokers
01445  *
01446  * @param $hook
01447  *   The hook being invoked.
01448  *
01449  * @return
01450  *   An array of info supplied by any hook implementations.
01451  */
01452 function panels_load_hooks($hook) {
01453   $info = array();
01454   foreach (module_implements($hook) as $module) {
01455     $result = _panels_process_plugin($module, $module, drupal_get_path('module', $module), $hook);
01456     if (is_array($result)) {
01457       $info = array_merge($info, $result);
01458     }
01459   }
01460   return $info;
01461 }
01462 
01463 /**
01464  * Process a single hook implementation of a panels plugin.
01465  *
01466  * @param $module
01467  *   The module that owns the hook.
01468  * @param $identifier
01469  *   Either the module or 'panels_' . $file->name
01470  * @param $hook
01471  *   The name of the hook being invoked.
01472  */
01473 function _panels_process_plugin($module, $identifier, $path, $hook) {
01474   $function = $identifier . '_' . $hook;
01475   if (!function_exists($function)) {
01476     return NULL;
01477   }
01478   $result = $function();
01479   if (!isset($result) || !is_array($result)) {
01480     return NULL;
01481   }
01482 
01483   // Fill in defaults.
01484   foreach ($result as $name => $plugin) {
01485     $result[$name]['module'] = $module;
01486     $result[$name]['name'] = $name;
01487     $result[$name]['path'] = $path;
01488     // Add some content type-specific defaults, but allow them to be overridden by declarations in the content type.
01489     if (preg_match('/content_type/', $hook)) {
01490       $result[$name] = array_merge(array('single' => FALSE, 'visibility serialize' => FALSE, 'role-based access' => TRUE), $result[$name]);
01491     }
01492   }
01493   return $result;
01494 }
01495 
01496 /**
01497  * Fetch a group of plugins by name.
01498  *
01499  * @param $plugin
01500  *   This is the name of the plugin, and also the name of the directory.
01501  * @param $hook
01502  *   This is the hook to call to get the info for the plugin.
01503  *
01504  * @return
01505  *   An array of information arrays about the plugins received.
01506  */
01507 function panels_get_plugins($plugin, $hook, $id = NULL) {
01508   static $plugins = array();
01509   static $all_hooks = array();
01510   static $all_files = array();
01511 
01512   // Always load all hooks if we need them.
01513   if (!isset($all_hooks[$plugin])) {
01514     $all_hooks[$plugin] = TRUE;
01515     $plugins[$plugin] = panels_load_hooks($hook);
01516   }
01517 
01518   // First, see if it's in our hooks before we even bother.
01519   if ($id && array_key_exists($id, $plugins[$plugin])) {
01520     return $plugins[$plugin][$id];
01521   }
01522 
01523   // Then see if we should load all files. We only do this if we
01524   // want a list of all plugins.
01525   if (!$id && empty($all_files[$plugin])) {
01526     $all_files[$plugin] = TRUE;
01527     $plugins[$plugin] = array_merge($plugins[$plugin], panels_load_includes($plugin, $hook));
01528   }
01529 
01530   // If no id was requested, we are finished here:
01531   if (!$id) {
01532     return $plugins[$plugin];
01533   }
01534 
01535   // Check to see if we need to look for the file
01536   if (!array_key_exists($id, $plugins[$plugin])) {
01537     $result = panels_load_includes($plugin, $hook, $id);
01538     // Set to either what was returned or NULL.
01539     $plugins[$plugin][$id] = isset($result[$id]) ? $result[$id] : NULL;
01540   }
01541 
01542   // At this point we should either have the plugin, or a NULL.
01543   return $plugins[$plugin][$id];
01544 }
01545 
01546 /**
01547  * Fetch a layout plugin
01548  *
01549  * @param $layout
01550  *   Name of a panel layout.
01551  *
01552  * @return
01553  *   An array with information about the requested panel layout.
01554  */
01555 function panels_get_layout($layout) {
01556   return panels_get_plugins('layouts', 'panels_layouts', $layout);
01557 }
01558 
01559 /**
01560  * Fetch all layout plugins
01561  *
01562  * @return
01563  *   An array of arrays with information about all available panel layouts.
01564  */
01565 function panels_get_layouts() {
01566   return panels_get_plugins('layouts', 'panels_layouts');
01567 }
01568 
01569 /**
01570  * Collate information about a specific panel style.
01571  *
01572  * @param $style
01573  *   Name of a panel style.
01574  *
01575  * @return
01576  *   An array with information about the requested panel style.
01577  */
01578 function panels_get_style($style) {
01579   return panels_get_plugins('styles', 'panels_styles', $style);
01580 }
01581 
01582 /**
01583  * Collate information about all available panel styles.
01584  *
01585  * @return
01586  *   An array of arrays with information about all available panel styles.
01587  */
01588 function panels_get_styles() {
01589   return panels_get_plugins('styles', 'panels_styles');
01590 }
01591 
01592 /**
01593  * Collate information about a specific panel argument.
01594  *
01595  * @param $argument
01596  *   Name of a panel argument.
01597  *
01598  * @return
01599  *   An array with information about the requested panel argument.
01600  */
01601 function panels_get_argument($argument) {
01602   return panels_get_plugins('arguments', 'panels_arguments', $argument);
01603 }
01604 
01605 /**
01606  * Collate information about all available panel arguments.
01607  *
01608  * @return
01609  *   An array of arrays with information about all available panel arguments.
01610  */
01611 function panels_get_arguments() {
01612   return panels_get_plugins('arguments', 'panels_arguments');
01613 }
01614 
01615 /**
01616  * Fetch a content_type plugin
01617  *
01618  * @param $content type
01619  *   Name of a panel content type.
01620  *
01621  * @return
01622  *   An array with information about the requested panel content type.
01623  */
01624 function panels_get_content_type($content_type) {
01625   return panels_get_plugins('content_types', 'panels_content_types', $content_type);
01626 }
01627 
01628 /**
01629  * Fetch all content type plugins
01630  *
01631  * @return
01632  *   An array of arrays with information about all available panel content types.
01633  */
01634 function panels_get_content_types() {
01635   return panels_get_plugins('content_types', 'panels_content_types');
01636 }
01637 
01638 /**
01639  * Fetch a relationship plugin
01640  *
01641  * @param $content type
01642  *   Name of a panel content type.
01643  *
01644  * @return
01645  *   An array with information about the requested relationship
01646  */
01647 function panels_get_relationship($relationship) {
01648   return panels_get_plugins('relationships', 'panels_relationships', $relationship);
01649 }
01650 
01651 /**
01652  * Fetch all relationship plugins
01653  *
01654  * @return
01655  *   An array of arrays with information about all available relationships.
01656  */
01657 function panels_get_relationships() {
01658   return panels_get_plugins('relationships', 'panels_relationships');
01659 }
01660 
01661 /**
01662  * Fetch a context plugin
01663  *
01664  * @param $context
01665  *   Name of a panel context.
01666  *
01667  * @return
01668  *   An array with information about the requested panel context.
01669  */
01670 function panels_get_context($context) {
01671   return panels_get_plugins('contexts', 'panels_contexts', $context);
01672 }
01673 
01674 /**
01675  * Fetch all context plugins
01676  *
01677  * @return
01678  *   An array of arrays with information about all available panel contexts.
01679  */
01680 function panels_get_contexts() {
01681   return panels_get_plugins('contexts', 'panels_contexts');
01682 }
01683 
01684 /**
01685  * Fetch a cache plugin
01686  *
01687  * @param $cache
01688  *   Name of a panel cache.
01689  *
01690  * @return
01691  *   An array with information about the requested panel cache.
01692  */
01693 function panels_get_cache($cache) {
01694   return panels_get_plugins('cache', 'panels_cache', $cache);
01695 }
01696 
01697 /**
01698  * Fetch all cache plugins
01699  *
01700  * @return
01701  *   An array of arrays with information about all available panel caches.
01702  */
01703 function panels_get_caches() {
01704   return panels_get_plugins('cache', 'panels_cache');
01705 }
01706 
01707 /**
01708  * Fetch a switcher plugin
01709  *
01710  * @param $switcher
01711  *   Name of a panel switcher.
01712  *
01713  * @return
01714  *   An array with information about the requested panel switcher.
01715  */
01716 function panels_get_switcher($switcher) {
01717   return panels_get_plugins('switchers', 'panels_switchers', $switcher);
01718 }
01719 
01720 /**
01721  * Fetch all switcher plugins
01722  *
01723  * @return
01724  *   An array of arrays with information about all available panel switchers.
01725  */
01726 function panels_get_switchers() {
01727   return panels_get_plugins('switchers', 'panels_switchers');
01728 }
01729 

Generated on Thu Feb 9 05:00:14 2012 for Panels 2 by  doxygen 1.5.6