Issue #1545544 by acrollet: prevent panelizer notice when using panelizer form widget.
[project/panelizer.git] / panelizer.module
1 <?php
2 /**
3 * @file
4 * The Panelizer module attaches panels to entities, providing default
5 * panels and allowing each panel to be configured independently by
6 * privileged users.
7 */
8
9 // -----------------------------------------------------------------------
10 // Drupal core hooks
11
12 /**
13 * Implements hook_permission().
14 */
15 function panelizer_permission() {
16 $items = array(
17 'administer panelizer' => array(
18 'title' => t('administer panelizer'),
19 'description' => t('Fully administer panelizer and all panelizer settings.'),
20 ),
21 );
22
23 // Delegate.
24 foreach (panelizer_get_plugins_with_hook('permission') as $handler) {
25 $handler->hook_permission($items);
26 }
27
28 return $items;
29 }
30
31 /**
32 * Implements hook_theme().
33 */
34 function panelizer_theme() {
35 $items = array();
36
37 $items['panelizer_settings_page_table'] = array(
38 'render element' => 'element',
39 'file' => 'includes/admin.inc',
40 );
41
42 // Delegate.
43 foreach (panelizer_get_plugins_with_hook('theme') as $handler) {
44 $handler->hook_theme($items);
45 }
46
47 return $items;
48 }
49
50 /**
51 * Implements hook_menu().
52 */
53 function panelizer_menu() {
54 $items = array();
55
56 // Delegate admin menu stuff to admin.inc
57 ctools_include('admin', 'panelizer');
58 panelizer_admin_hook_menu($items);
59
60 // Delegate.
61 foreach (panelizer_get_plugins_with_hook('menu') as $handler) {
62 $handler->hook_menu($items);
63 }
64
65 return $items;
66 }
67
68 /**
69 * Implements hook_menu_alter().
70 */
71 function panelizer_menu_alter(&$items) {
72 // Delegate.
73 foreach (panelizer_get_plugins_with_hook('menu_alter') as $handler) {
74 $handler->hook_menu_alter($items);
75 }
76 }
77
78 /**
79 * Implements hook_admin_paths().
80 */
81 function panelizer_admin_paths() {
82 $items = array();
83
84 // Delegate.
85 foreach (panelizer_get_plugins_with_hook('admin_paths') as $handler) {
86 $handler->hook_admin_paths($items);
87 }
88
89 return $items;
90 }
91
92 /**
93 * Implements hook_form_alter().
94 */
95 function panelizer_form_alter(&$form, &$form_state, $form_id) {
96 // Delegate.
97 foreach (panelizer_get_plugins_with_hook('form_alter') as $handler) {
98 $handler->hook_form_alter($form, $form_state, $form_id);
99 }
100 }
101
102 /**
103 * Implements hook_page_alter().
104 */
105 function panelizer_page_alter(&$page) {
106 // Delegate.
107 foreach (panelizer_get_plugins_with_hook('page_alter') as $handler) {
108 $handler->hook_page_alter($page);
109 }
110 }
111
112 /**
113 * Implements hook_entity_load().
114 */
115 function panelizer_entity_load(&$entities, $entity_type) {
116 // Delegate to the handler.
117 if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
118 $handler->hook_entity_load($entities);
119 }
120 }
121
122 /**
123 * Implements hook_entity_update().
124 */
125 function panelizer_entity_update($entity, $entity_type) {
126 // Delegate to the handler.
127 if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
128 $handler->hook_entity_update($entity);
129 }
130 }
131
132 /**
133 * Implements hook_entity_insert().
134 */
135 function panelizer_entity_insert($entity, $entity_type) {
136 // Delegate to the handler.
137 if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
138 $handler->hook_entity_insert($entity);
139 }
140 }
141
142 /**
143 * Implements hook_entity_delete().
144 */
145 function panelizer_entity_delete($entity, $entity_type) {
146 // Delegate to the handler.
147 if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
148 $handler->hook_entity_delete($entity);
149 }
150 }
151
152 /**
153 * Implements hook_field_attach_delete_revision().
154 */
155 function panelizer_field_attach_delete_revision($entity_type, $entity) {
156 // Delegate to the handler.
157 if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
158 $handler->hook_field_attach_delete_revision($entity);
159 }
160 }
161
162 function panelizer_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
163 // Delegate to the handler.
164 if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
165 $handler->hook_field_attach_form($entity, $form, $form_state, $langcode);
166 }
167 }
168
169 function panelizer_field_attach_submit($entity_type, $entity, &$form, &$form_state) {
170 // Delegate to the handler.
171 if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
172 $handler->hook_field_attach_submit($entity, $form, $form_state);
173 }
174 }
175
176 // -----------------------------------------------------------------------
177 // Panels and CTools hooks
178
179 /**
180 * Implements hook_ctools_plugin_type()
181 */
182 function panelizer_ctools_plugin_type() {
183 $items['entity'] = array(
184 'cache' => FALSE,
185 'process' => array(
186 'function' => 'panelizer_entity_plugin_process',
187 ),
188 'classes' => array('handler'),
189 );
190
191 return $items;
192 }
193
194 /**
195 * Implements hook_ctools_plugin_directory()
196 */
197 function panelizer_ctools_plugin_directory($module, $plugin) {
198 if (in_array($module, array('panelizer', 'ctools', 'page_manager'))) {
199 return 'plugins/' . $plugin;
200 }
201 }
202
203 /**
204 * Implements hook_ctools_plugin_api().
205 */
206 function panelizer_ctools_plugin_api($module, $api) {
207 if (($module == 'page_manager' && $api == 'pages_default') || $module == 'panelizer') {
208 return array(
209 'version' => 1,
210 'path' => drupal_get_path('module', 'panelizer') . '/includes',
211 );
212 }
213 }
214
215 /**
216 * Implements hook_features_api().
217 */
218 function panelizer_features_api() {
219 $api = array();
220 $api['panelizer_defaults'] = _ctools_features_get_info('panelizer_defaults');
221 $api['panelizer_defaults']['alter_type'] = FEATURES_ALTER_TYPE_NONE;
222
223 return $api;
224 }
225
226 /**
227 * Implementation of hook_views_api().
228 */
229 function panelizer_views_api() {
230 return array(
231 'api' => 2.0,
232 'path' => drupal_get_path('module', 'panelizer') . '/plugins/views',
233 );
234 }
235
236 /**
237 * Implements hook_panelizer_defaults_alter().
238 */
239 function panelizer_panelizer_defaults_alter(&$items) {
240 // Delegate.
241 foreach (panelizer_get_plugins_with_hook('panelizer_defaults') as $handler) {
242 $handler->hook_panelizer_defaults($items);
243 }
244 }
245
246 /**
247 * Implements hook_default_page_manager_handlers().
248 */
249 function panelizer_default_page_manager_handlers() {
250 $items = array();
251 // Delegate.
252 foreach (panelizer_get_plugins_with_hook('default_page_manager_handlers') as $handler) {
253 $handler->hook_default_page_manager_handlers($items);
254 }
255
256 return $items;
257 }
258
259 /**
260 * Implement CTools access form caching callback: get.
261 */
262 function panelizer_ctools_access_get($argument) {
263 list($entity_type, $bundle, $name) = explode(':', $argument);
264 $handler = panelizer_entity_plugin_get_handler($entity_type);
265 $panelizer = $handler->get_default_panelizer_object($bundle, $name);
266
267 if (empty($panelizer)) {
268 return;
269 }
270
271 if (!$handler->access_default_panelizer_object($panelizer)) {
272 return;
273 }
274
275 // First, see if there's a cache
276 ctools_include('object-cache');
277 $access = ctools_object_cache_get('panelizer_access', $argument);
278 if (!$access) {
279 $access = $panelizer->access;
280 }
281
282 $context = $handler->get_contexts($panelizer);
283
284 return array($access, $context);
285 }
286
287 /**
288 * Implement CTools access form caching callback: set.
289 */
290 function panelizer_ctools_access_set($argument, $access) {
291 list($entity_type, $bundle, $name) = explode(':', $argument);
292 $handler = panelizer_entity_plugin_get_handler($entity_type);
293 $panelizer = $handler->get_default_panelizer_object($bundle, $name);
294
295 if (empty($panelizer)) {
296 return;
297 }
298
299 if (!$handler->access_default_panelizer_object($panelizer)) {
300 return;
301 }
302
303 ctools_include('object-cache');
304 ctools_object_cache_set('panelizer_access', $argument, $access);
305 }
306
307 /**
308 * Implement CTools access form caching callback: get.
309 */
310 function panelizer_ctools_access_clear($argument) {
311 list($entity_type, $bundle, $name) = explode(':', $argument);
312 $handler = panelizer_entity_plugin_get_handler($entity_type);
313 $panelizer = $handler->get_default_panelizer_object($bundle, $name);
314
315 if (empty($panelizer)) {
316 return;
317 }
318
319 if (!$handler->access_default_panelizer_object($panelizer)) {
320 return;
321 }
322
323 ctools_include('object-cache');
324 ctools_object_cache_clear('panelizer', $argument);
325 }
326
327 // -----------------------------------------------------------------------
328 // CTools entity plugin support code
329
330 /**
331 * CTools process callback for an entity plugin.
332 *
333 * This adds configuration data to the plugin so that we know what
334 * bundles it is enabled for.
335 */
336 function panelizer_entity_plugin_process(&$plugin, $info) {
337 $entity_type = $plugin['name'];
338 $entity_info = entity_get_info($entity_type);
339 $plugin['bundles'] = array();
340 if ($entity_info) {
341 foreach ($entity_info['bundles'] as $bundle => $label) {
342 if ($settings = variable_get('panelizer_defaults_' . $entity_type . '_' . $bundle, array())) {
343 $plugin['bundles'][$bundle] = $settings;
344 }
345 }
346 }
347
348 drupal_alter('panelizer_entity_plugin_process', $plugin, $info);
349 }
350
351 /**
352 * Fetch a single entity plugin.
353 */
354 function panelizer_get_entity_plugin($entity_type) {
355 ctools_include('plugins');
356 return ctools_get_plugins('panelizer', 'entity', $entity_type);
357 }
358
359 /**
360 * Fetch all entity plugin.
361 */
362 function panelizer_get_entity_plugins() {
363 ctools_include('plugins');
364 return ctools_get_plugins('panelizer', 'entity');
365 }
366
367 /**
368 * Get the class to handle custom code for a given entity type plugin.
369 *
370 * If a plugin does not define a class at all, then the default class
371 *
372 * @return
373 * Either the instantiated handler or FALSE if one could not be had.
374 */
375 function panelizer_entity_plugin_get_handler($plugin) {
376 // The default plugin handler is abstract and cannot be loaded.
377 if ($plugin == 'default') {
378 return;
379 }
380
381 $cache = &drupal_static(__FUNCTION__, array());
382
383 // If a string was passed, turn it into a plugin.
384 if (is_string($plugin)) {
385 $plugin = panelizer_get_entity_plugin($plugin);
386 if (!$plugin) {
387 return FALSE;
388 }
389 }
390
391 // Get the class name from the 'handler' property if we have not already
392 // cached a handler.
393 if (is_object($plugin)) {
394 vpr_trace();
395 exit;
396 }
397 if (empty($cache[$plugin['name']]) && ($class = ctools_plugin_get_class($plugin, 'handler'))) {
398 // @todo is there a good reason to use ->init instead of __construct?
399 $cache[$plugin['name']] = new $class();
400 $cache[$plugin['name']]->init($plugin);
401 }
402 return !empty($cache[$plugin['name']]) ? $cache[$plugin['name']] : FALSE;
403 }
404
405 /**
406 * Load handler to get a plugin as a menu callback.
407 */
408 function panelizer_handler_load($entity_type) {
409 return panelizer_entity_plugin_get_handler($entity_type);
410 }
411
412 /**
413 * Fetch handler objects for all plugins that implement the named hook.
414 *
415 * These plugins must set $plugin['hooks'][$hook] = TRUE in order to
416 * be instantiated.
417 *
418 * This is only called for system wide hooks such as hook_menu and
419 * hook_menu_alter; entity specific hooks will always be called.
420 */
421 function panelizer_get_plugins_with_hook($hook) {
422 $objects = array();
423 $plugins = panelizer_get_entity_plugins();
424 foreach ($plugins as $entity_type => $plugin) {
425 if (!empty($plugin['hooks'][$hook])) {
426 if ($handler = panelizer_entity_plugin_get_handler($plugin)) {
427 $objects[$entity_type] = $handler;
428 }
429 }
430 }
431
432 return $objects;
433 }
434
435 /**
436 * Page callback for entity menu callbacks.
437 *
438 * This function is to be used as a menu callback for menu items that
439 * are to be handled by a method on the handler object. It loads the object
440 * defined in the plugin and hands it off to a method based upon the name
441 * of the operation in use.
442 *
443 * For example, if the 'op' is 'revision' then the callback method will be
444 * 'page_revisions', with all of the arguments *except* the $op and the
445 * plugin name.
446 */
447 function panelizer_entity_plugin_switcher_page($entity_type, $op) {
448 $args = func_get_args();
449 $js = !empty($_REQUEST['js']);
450
451 // Load the $plugin information
452 if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
453 $method = 'page_' . $op;
454 if (method_exists($handler, $method)) {
455 // replace the first two arguments:
456 $args[0] = $js;
457 $args[1] = $_POST;
458 return call_user_func_array(array($handler, $method), $args);
459 }
460 }
461 else {
462 return t('Configuration error. No handler found.');
463 }
464 }
465
466 /**
467 * Callback used for switching callbacks into the proper plugin.
468 */
469 function panelizer_entity_plugin_callback_switcher($entity_type, $switcher_type, $op) {
470 $args = func_get_args();
471 if (count($args) < 3) {
472 return FALSE;
473 }
474 $entity_type = array_shift($args);
475 $switcher_type = array_shift($args);
476 $op = array_shift($args);
477
478 // Load the $plugin information
479 if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
480 $method = $switcher_type . '_' . $op;
481 if (method_exists($handler, $method)) {
482 return call_user_func_array(array($handler, $method), $args);
483 }
484 }
485 else {
486 return FALSE;
487 }
488 }
489
490 /**
491 * Specialized version of ctools_export_ui_switcher_page()
492 *
493 * This one is designed to set our entity handler and bundle on the
494 * object so we can refer to it later without having to override
495 * all of the entry points.
496 */
497 function panelizer_export_ui_switcher_page($entity_handler, $bundle, $plugin_name, $op) {
498 $args = func_get_args();
499
500 // Remove the handler and the bundle.
501 array_shift($args);
502 array_shift($args);
503 $js = !empty($_REQUEST['js']);
504
505 // Load the $plugin information
506 $plugin = ctools_get_export_ui($plugin_name);
507 $handler = ctools_export_ui_get_handler($plugin);
508
509 if ($handler) {
510 if (is_string($entity_handler)) {
511 $entity_handler = panelizer_entity_plugin_get_handler($entity_handler);
512 }
513
514 $handler->entity_handler = $entity_handler;
515 $handler->entity_bundle = $bundle;
516 if (empty($entity_handler->entity_admin_root) || substr($_GET['q'], 30) == 'admin/config/content/panelizer') {
517 $handler->plugin['menu']['menu prefix'] = 'admin/config/content/panelizer/' . $entity_handler->entity_type;
518 $handler->plugin['menu']['menu item'] = $bundle;
519 }
520 else {
521 $base_path = $entity_handler->entity_admin_root . '/panelizer';
522 if (is_numeric($entity_handler->entity_admin_bundle)) {
523 $bits = explode('/', $base_path);
524 $bits[$entity_handler->entity_admin_bundle] = $bundle;
525 $base_path = implode('/', $bits);
526 }
527 $handler->plugin['menu']['menu prefix'] = dirname($base_path);
528 $handler->plugin['menu']['menu item'] = basename($base_path);
529 }
530
531 $path = $handler->plugin['menu']['menu prefix'] . '/' . $handler->plugin['menu']['menu item'];
532
533 foreach ($handler->plugin['redirect'] as $key => $old_path) {
534 if ($key == 'add') {
535 $handler->plugin['redirect'][$key] = $path . '/list/%ctools_export_ui/settings';
536 }
537 else {
538 $handler->plugin['redirect'][$key] = $path . '/list';
539 }
540 }
541
542 $method = $op . '_page';
543 if (method_exists($handler, $method)) {
544 // replace the first two arguments:
545 $args[0] = $js;
546 $args[1] = $_POST;
547 return call_user_func_array(array($handler, $method), $args);
548 }
549 }
550 else {
551 return t('Configuration error. No handler found.');
552 }
553 }
554
555 // ---------------------------------------------------------------------------
556 // Menu callbacks
557
558 /**
559 * Title callback to properly set the tile when editing panelizer defaults.
560 */
561 function panelizer_default_title_callback($handler, $bundle) {
562 if (is_string($handler)) {
563 $handler = panelizer_entity_plugin_get_handler($handler);
564 }
565
566 if (!$handler) {
567 return '';
568 }
569
570 $title = $handler->get_bundle_title($bundle);
571 return $title;
572 }
573
574 /**
575 * Menu callback to determine if a type has a choice of defaults.
576 *
577 * We use this to make sure the right tabs appear.
578 */
579 function panelizer_has_choice_callback($handler, $bundle, $name = NULL) {
580 if (is_string($handler)) {
581 $handler = panelizer_entity_plugin_get_handler($handler);
582 }
583
584 if (!$handler) {
585 return FALSE;
586 }
587
588 if (!panelizer_administer_entity_bundle($handler, $bundle)) {
589 return FALSE;
590 }
591
592 // Check to see if $name is valid
593 if ($name && !$handler->get_default_panelizer_object($bundle, $name)) {
594 return FALSE;
595 }
596
597 return $handler->has_panel_choice($bundle);
598 }
599
600 /**
601 * Menu callback to determine if a type has a choice of defaults.
602 *
603 * We use this to make sure the right tabs appear.
604 */
605 function panelizer_has_no_choice_callback($handler, $bundle) {
606 if (is_string($handler)) {
607 $handler = panelizer_entity_plugin_get_handler($handler);
608 }
609
610 if (!$handler) {
611 return FALSE;
612 }
613
614 if (!panelizer_administer_entity_bundle($handler, $bundle)) {
615 return FALSE;
616 }
617
618 return $handler->has_default_panel($bundle) && !$handler->has_panel_choice($bundle);
619 }
620
621 /**
622 * Menu callback to determine if a type has a choice of defaults.
623 *
624 * We use this to make sure the right tabs appear.
625 */
626 function panelizer_is_panelized($handler, $bundle) {
627 if (is_string($handler)) {
628 $handler = panelizer_entity_plugin_get_handler($handler);
629 }
630
631 if (!$handler) {
632 return FALSE;
633 }
634
635 if (!panelizer_administer_entity_bundle($handler, $bundle)) {
636 return FALSE;
637 }
638
639 return $handler->is_panelized($bundle);
640 }
641
642 /**
643 * Access callback to see if a user can administer a particular bundle.
644 */
645 function panelizer_administer_entity_bundle($handler, $bundle) {
646 if (is_string($handler)) {
647 $handler = panelizer_entity_plugin_get_handler($handler);
648 }
649
650 return user_access('administer panelizer') || user_access("administer panelizer $handler->entity_type $bundle defaults");
651 }
652
653 /**
654 * Access callback to see if a user can administer a particular panelizer default.
655 */
656 function panelizer_administer_panelizer_default($handler, $bundle, $name) {
657 if (is_string($handler)) {
658 $handler = panelizer_entity_plugin_get_handler($handler);
659 }
660
661 $panelizer = $handler->get_default_panelizer_object($bundle, $name);
662 if (!$panelizer) {
663 return FALSE;
664 }
665
666 return $handler->access_default_panelizer_object($panelizer);
667 }
668
669 /**
670 * Menu load callback to scrub a node bundle from the URL safe equivalent.
671 */
672 function panelizer_node_type_load($name) {
673 if ($type = node_type_get_type(strtr($name, array('-' => '_')))) {
674 return $type->type;
675 }
676 }
677
678 // ---------------------------------------------------------------------------
679 // export.inc callbacks to handle proper in/out of our defaults
680
681 /**
682 * export.inc callback to properly save a panelizer default.
683 */
684 function panelizer_export_save_callback(&$object) {
685 if (!empty($object->display)) {
686 // First write the display
687 panels_save_display($object->display);
688
689 // Make sure we have the did.
690 $object->did = $object->display->did;
691 }
692
693 // Then write the default
694 if ($object->export_type & EXPORT_IN_DATABASE) {
695 // Existing record.
696 $update = array('pnid');
697 }
698 else {
699 // New record.
700 $update = array();
701 $object->export_type = EXPORT_IN_DATABASE;
702 }
703
704 return drupal_write_record('panelizer_defaults', $object, $update);
705 }
706
707 /**
708 * export.inc callback to properly export a panelizer default.
709 */
710 function panelizer_export_export_callback($object, $indent) {
711 $object->did = NULL;
712 $output = ctools_export_object('panelizer_defaults', $object, $indent);
713 $output .= panels_export_display($object->display, $indent);
714 $output .= $indent . '$panelizer->display = $display;' . "\n";
715
716 return $output;
717 }
718
719 /**
720 * export.inc callback to properly delete a panelizer default.
721 */
722 function panelizer_export_delete_callback($object) {
723 if (!empty($object->did)) {
724 panels_delete_display($object->did);
725 }
726
727 db_delete('panelizer_defaults')
728 ->condition('name', $object->name)
729 ->execute();
730 }
731
732 /**
733 * export.inc callback to load sub records for an object.
734 */
735 function panelizer_export_delete_callback_subrecords($objects) {
736 $dids = array();
737 foreach ($objects as $panelizer) {
738 if (!empty($panelizer->did)) {
739 $dids[$panelizer->did] = $panelizer->did;
740 }
741 }
742
743 if ($dids) {
744 $displays = panels_load_displays($dids);
745 foreach ($objects as $panelizer) {
746 if (!empty($panelizer->did) && !empty($displays[$panelizer->did])) {
747 $panelizer->display = $displays[$panelizer->did];
748 }
749 }
750 }
751 }
752
753 // ---------------------------------------------------------------------------
754 // Context cache callbacks -- this really needs a less lame system someday.
755
756 /**
757 * Fetch the panelizer object from the object cache.
758 *
759 * CTools clumsy context editing system requires caching. This lets us
760 * do it reasonably.
761 *
762 * @param $entity_type
763 * Can be something like 'node' or 'user' or 'default'.
764 * @param $key
765 * Depends on the $entity_type. Can be a nid, a uid or a default key.
766 */
767 function panelizer_context_cache_get($entity_type, $key) {
768 ctools_include('object-cache');
769 $cache = ctools_object_cache_get('panelizer_context_cache', $entity_type . ':' . $key);
770 if (!empty($cache)) {
771 $cache->cached = TRUE;
772 return $cache;
773 }
774
775 if ($entity_type == 'default') {
776 list($entity_type, $bundle, $name) = @explode(':', $key, 3);
777 $get_default = TRUE;
778 }
779
780 if ($handler = panelizer_entity_plugin_get_handler($entity_type)) {
781 if (!empty($get_default)) {
782 $panelizer = $handler->get_default_panelizer_object($bundle, $name);
783 $panelizer->base_contexts = $handler->get_base_contexts();
784 return $panelizer;
785 }
786 else {
787 $entities = entity_load($entity_type, array($key));
788 if ($entities[$key] && $entities[$key]->panelizer) {
789 $panelizer = $entities[$key]->panelizer;
790 $panelizer->base_contexts = $handler->get_base_contexts($entities[$key]);
791 return $panelizer;
792 }
793 }
794 }
795 }
796
797 /**
798 * Store the panelizer object in the object cache.
799 *
800 * CTools clumsy context editing system requires caching. This lets us
801 * do it reasonably.
802 *
803 * @param $entity_type
804 * Can be something like 'node' or 'user' or 'default'.
805 * @param $key
806 * Either the node type or the nid.
807 * @param $object
808 * The cached object.
809 */
810 function panelizer_context_cache_set($entity_type, $key, $object) {
811 ctools_include('object-cache');
812 ctools_object_cache_set('panelizer_context_cache', $entity_type . ':' . $key, $object);
813 }
814
815 /**
816 * Clear the panelizer object in the object cache.
817 *
818 * CTools clumsy context editing system requires caching. This lets us
819 * do it reasonably.
820 *
821 * @param $entity_type
822 * Can be something like 'node' or 'user' or 'default'.
823 * @param $key
824 * Either the node type or the nid.
825 */
826 function panelizer_context_cache_clear($entity_type, $key) {
827 ctools_include('object-cache');
828 ctools_object_cache_clear('panelizer_context_cache', $entity_type . ':' . $key);
829 }
830
831 // --------------------------------------------------------------------------
832 // Panels edit cache contexts.
833
834 /**
835 * Get display edit cache for a panel being edited.
836 *
837 * The key is the second half of the key in this form:
838 * panelizer:TYPE:KEY;
839 */
840 function panelizer_panels_cache_get($argument) {
841 ctools_include('object-cache');
842 list($entity_type, $key) = explode(':', $argument, 2);
843 $cache = ctools_object_cache_get('panelizer_display_cache', $entity_type . ':' . $key);
844
845 // Keep $type because $entity_type can be 'default' which is not actually an
846 // entity type in that case.
847 $type = $entity_type;
848 if ($entity_type == 'default') {
849 list($entity_type, $bundle, $name) = @explode(':', $key, 3);
850 $get_default = TRUE;
851 }
852
853 $handler = panelizer_entity_plugin_get_handler($entity_type);
854 if (!$handler) {
855 return;
856 }
857
858 // If it's already cached, we still need to restore our contexts.
859 if (!empty($cache)) {
860 $cache->cached = TRUE;
861 if (!empty($get_default)) {
862 $panelizer = $handler->get_default_panelizer_object($bundle, $name);
863 $cache->display->context = $handler->get_contexts($panelizer);
864 }
865 else {
866 $entities = entity_load($entity_type, array($key));
867 if ($entities[$key] && $entities[$key]->panelizer) {
868 $panelizer = $entities[$key]->panelizer;
869 $cache->display->context = $handler->get_contexts($panelizer, $entities[$key]);
870 }
871 }
872
873 return $cache;
874 }
875
876 $cache = new stdClass();
877
878 // If it wasn't cached, create a new cache.
879 if (!empty($get_default)) {
880 $panelizer = $handler->get_default_panelizer_object($bundle, $name);
881 $cache->display = $panelizer->display;
882 $cache->display->context = $handler->get_contexts($panelizer);
883 }
884 else {
885 $entities = entity_load($entity_type, array($key));
886 if (empty($entities[$key]) || empty($entities[$key]->panelizer)) {
887 return $cache;
888 }
889
890 list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entities[$key]);
891 $panelizer = $entities[$key]->panelizer;
892 $cache->display = $panelizer->display;
893 $cache->display->context = $handler->get_contexts($panelizer, $entities[$key]);
894 }
895
896 ctools_include('common', 'panels');
897 $cache->display->cache_key = "panelizer:$type:$key";
898 $cache->content_types = panels_common_get_allowed_types('panelizer_' . $type . ':' . $bundle, $cache->display->context);
899
900 return $cache;
901 }
902
903 /**
904 * Store a display edit in progress in the page cache.
905 */
906 function panelizer_panels_cache_set($argument, $cache) {
907 list($type, $key) = explode(':', $argument, 2);
908 ctools_include('object-cache');
909 ctools_object_cache_set('panelizer_display_cache', $type . ':' . $key, $cache);
910 }
911
912 /**
913 * Save all changes made to a display using the Page Manager page cache.
914 */
915 function panelizer_panels_cache_clear($argument, $cache) {
916 list($type, $key) = explode(':', $argument, 2);
917 ctools_include('object-cache');
918 ctools_object_cache_clear('panelizer_display_cache', $type . ':' . $key);
919 }
920
921 /**
922 * Save all changes made to a display using the Page Manager page cache.
923 */
924 function panelizer_panels_cache_save($argument, $cache) {
925 list($entity_type, $key) = explode(':', $argument, 2);
926 $type = $entity_type;
927 if ($entity_type == 'default') {
928 list($entity_type, $bundle, $name) = @explode(':', $key, 3);
929 $get_default = TRUE;
930 }
931
932 $handler = panelizer_entity_plugin_get_handler($entity_type);
933 if (!$handler) {
934 return;
935 }
936
937 if (!empty($get_default)) {
938 $panelizer = $handler->get_default_panelizer_object($bundle, $name);
939 $panelizer->display = $cache->display;
940 ctools_include('export');
941 ctools_export_crud_save('panelizer_defaults', $panelizer);
942 }
943 else {
944 $entities = entity_load($entity_type, array($key));
945 if ($entities[$key] && $entities[$key]->panelizer) {
946 $entities[$key]->panelizer->display = $cache->display;
947 $entities[$key]->panelizer->display_is_modified = TRUE;
948 $handler->entity_save($entities[$key]);
949 }
950 }
951 panelizer_panels_cache_clear($argument, $cache);
952
953 }
954
955 // ---------------------------------------------------------------------------
956 // Contrib module hooks to provide needed functionality.
957
958
959 /**
960 * Implements hook_export_node_alter().
961 *
962 * Integrate with export.module for saving panel_nodes into code.
963 */
964 function panelizer_export_node_alter(&$node, $original_node, $method) {
965 // @todo
966 }
967
968 /**
969 * Implements hook_panelizer_defaults_alter().
970 *
971 * Remove the panels node because there is no point to panelizing it.
972 */
973 function panelizer_panelizer_default_types_alter(&$bundles, $entity_type) {
974 switch ($entity_type) {
975 case 'node':
976 // Disallow the panel node type, since it's already a panel.
977 if (module_exists('panels_node') && !empty($bundles['panel'])) {
978 unset($bundles['panel']);
979 }
980 break;
981 case 'user':
982 }
983 }
984
985 /**
986 * Implements hook_features_export_alter().
987 */
988 function panelizer_features_export_alter(&$export, $module_name) {
989 if (!empty($export['features']['panelizer_defaults'])) {
990 foreach ($export['features']['panelizer_defaults'] as $machine_name) {
991 list ($entity_type, $bundle) = explode(':', $machine_name);
992
993 $variables = array(
994 'panelizer_defaults_' . $entity_type . '_' . $bundle,
995 'panelizer_' . $entity_type . ':' . $bundle . '_allowed_layouts',
996 'panelizer_' . $entity_type . ':' . $bundle . '_allowed_types',
997 'panelizer_' . $entity_type . ':' . $bundle . '_default'
998 );
999
1000 if (module_exists('strongarm')) {
1001 foreach ($variables as $key => $variable) {
1002 if (variable_get($variable) === NULL) {
1003 unset($variables[$key]);
1004 }
1005 }
1006 $variables = array_diff($variables, array_keys(strongarm_vars_load()));
1007 }
1008
1009 foreach ($variables as $variable) {
1010 $export['features']['variable'][$variable] = $variable;
1011 }
1012 }
1013 }
1014
1015 return array();
1016 }
1017
1018 // -----------------------------------------------------------------------
1019 // Drupal actions integration for VBO
1020
1021 /**
1022 * Implements hook_action_info().
1023 */
1024 function panelizer_action_info() {
1025 return array(
1026 'panelizer_set_status_action' => array(
1027 'type' => 'entity',
1028 'label' => t('Set panelizer status'),
1029 'vbo_configurable' => TRUE,
1030 'behavior' => array('changes_property'),
1031 'configurable' => TRUE,
1032 )
1033 );
1034 }
1035
1036 /**
1037 * Executes the panelizer_set_status action.
1038 */
1039 function panelizer_set_status_action($entity, $context) {
1040 list($entity_id, $revision_id, $bundle) = entity_extract_ids($context['entity_type'], $entity);
1041 if (isset($context['panelizer_default'])) {
1042 $entity->panelizer = $context['panelizer_default'];
1043 $entity->panelizer->did = NULL;
1044
1045 // Ensure original values are maintained:
1046 $entity->panelizer->entity_id = $entity_id;
1047 $entity->panelizer->revision_id = $revision_id;
1048 }
1049 else {
1050 $entity->panelizer->name = NULL;
1051 $entity->panelizer->did = NULL;
1052 }
1053 }
1054
1055 /**
1056 * Provides the panelizer_set_status_action form.
1057 */
1058 function panelizer_set_status_action_form($context, &$form_state) {
1059 $form = array();
1060 $entity_info = entity_get_info($context['entity_type']);
1061 $entities = entity_load($context['entity_type'], $form_state['selection']);
1062 $bundles = array();
1063
1064 // Collect our list of bundles.
1065 foreach ($entities as $entity) {
1066 list($entity_id, $revision_id, $bundle) = entity_extract_ids($context['entity_type'], $entity);
1067 $bundles[$bundle] = $bundle;
1068 }
1069
1070 $conditions = array(
1071 'panelizer_type' => $context['entity_type'],
1072 'panelizer_key' => $bundles,
1073 );
1074
1075 ctools_include('export');
1076 $defaults = ctools_export_load_object('panelizer_defaults', 'conditions', $conditions);
1077
1078 foreach ($defaults as $name => $default) {
1079 if (empty($default->title)) {
1080 $default->title = t('Default');
1081 }
1082 $options[$name] = t('@bundle: @title', array('@bundle' => $entity_info['bundles'][$default->panelizer_key]['label'], '@title' => $default->title));
1083 }
1084
1085 natcasesort($options);
1086 $options = array(
1087 'not' => t('Not panelized'),
1088 ) + $options;
1089
1090 $form['panelizer'] = array(
1091 '#type' => 'select',
1092 '#title' => t('Panelizer status'),
1093 '#options' => $options,
1094 );
1095
1096 $form['#panelizer_defaults'] = $defaults;
1097 return $form;
1098 }
1099
1100 function panelizer_set_status_action_submit($form, $form_state) {
1101 $retval = array(
1102 'panelizer' => $form_state['values']['panelizer'],
1103 );
1104
1105 if ($form_state['values']['panelizer'] != 'not') {
1106 $retval['panelizer_default'] = $form['#panelizer_defaults'][$form_state['values']['panelizer']];
1107 }
1108
1109 return $retval;
1110 }
1111