| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: export.inc,v 1.19.2.23 2010/08/12 20:48:31 merlinofchaos Exp $ 3 4 /** 5 * @file 6 * Contains code to make it easier to have exportable objects. 7 * 8 * Documentation for exportable objects is contained in help/export.html 9 */ 10 11 /** 12 * A bit flag used to let us know if an object is in the database. 13 */ 14 define('EXPORT_IN_DATABASE', 0x01); 15 16 /** 17 * A bit flag used to let us know if an object is a 'default' in code. 18 */ 19 define('EXPORT_IN_CODE', 0x02); 20 21 /** 22 * @defgroup export_crud CRUD functions for export. 23 * @{ 24 * export.inc supports a small number of CRUD functions that should always 25 * work for every exportable object, no matter how complicated. These 26 * functions allow complex objects to provide their own callbacks, but 27 * in most cases, the default callbacks will be used. 28 * 29 * Note that defaults are NOT set in the $schema because it is presumed 30 * that a module's personalized CRUD functions will already know which 31 * $table to use and not want to clutter up the arguments with it. 32 */ 33 34 /** 35 * Create a new object for the given $table. 36 * 37 * @param $table 38 * The name of the table to use to retrieve $schema values. This table 39 * must have an 'export' section containing data or this function 40 * will fail. 41 * @param $set_defaults 42 * If TRUE, which is the default, then default values will be retrieved 43 * from schema fields and set on the object. 44 * 45 * @return 46 * The loaded object. 47 */ 48 function ctools_export_crud_new($table, $set_defaults = TRUE) { 49 $schema = ctools_export_get_schema($table); 50 $export = $schema['export']; 51 52 if (!empty($export['create callback']) && function_exists($export['create callback'])) { 53 return $export['create callback']($set_defaults); 54 } 55 else { 56 return ctools_export_new_object($table, $set_defaults); 57 } 58 } 59 60 /** 61 * Load a single exportable object. 62 * 63 * @param $table 64 * The name of the table to use to retrieve $schema values. This table 65 * must have an 'export' section containing data or this function 66 * will fail. 67 * @param $name 68 * The unique ID to load. The field for this ID will be specified by 69 * the export key, which normally defaults to 'name'. 70 * 71 * @return 72 * The loaded object. 73 */ 74 function ctools_export_crud_load($table, $name) { 75 $schema = ctools_export_get_schema($table); 76 $export = $schema['export']; 77 78 if (!empty($export['load callback']) && function_exists($export['load callback'])) { 79 return $export['load callback']($name); 80 } 81 else { 82 $result = ctools_export_load_object($table, 'names', array($name)); 83 if (isset($result[$name])) { 84 return $result[$name]; 85 } 86 } 87 } 88 89 /** 90 * Load all exportable objects of a given type. 91 * 92 * @param $table 93 * The name of the table to use to retrieve $schema values. This table 94 * must have an 'export' section containing data or this function 95 * will fail. 96 * @param $reset 97 * If TRUE, the static cache of all objects will be flushed prior to 98 * loading all. This can be important on listing pages where items 99 * might have changed on the page load. 100 * @return 101 * An array of all loaded objects, keyed by the unique IDs of the export key. 102 */ 103 function ctools_export_crud_load_all($table, $reset = FALSE) { 104 $schema = ctools_export_get_schema($table); 105 if (empty($schema['export'])) { 106 return array(); 107 } 108 109 $export = $schema['export']; 110 111 if ($reset) { 112 ctools_export_load_object_reset($table); 113 } 114 115 if (!empty($export['load all callback']) && function_exists($export['load all callback'])) { 116 return $export['load all callback']($reset); 117 } 118 else { 119 return ctools_export_load_object($table, 'all'); 120 } 121 } 122 123 /** 124 * Save a single exportable object. 125 * 126 * @param $table 127 * The name of the table to use to retrieve $schema values. This table 128 * must have an 'export' section containing data or this function 129 * will fail. 130 * @param $object 131 * The fully populated object to save. 132 * 133 * @return 134 * Failure to write a record will return FALSE. Otherwise SAVED_NEW or 135 * SAVED_UPDATED is returned depending on the operation performed. The 136 * $object parameter contains values for any serial fields defined by the $table 137 */ 138 function ctools_export_crud_save($table, &$object) { 139 $schema = ctools_export_get_schema($table); 140 $export = $schema['export']; 141 142 if (!empty($export['save callback']) && function_exists($export['save callback'])) { 143 return $export['save callback']($object); 144 } 145 else { 146 // Objects should have a serial primary key. If not, simply fail to write. 147 if (empty($export['primary key'])) { 148 return FALSE; 149 } 150 151 $key = $export['primary key']; 152 if ($object->export_type & EXPORT_IN_DATABASE) { 153 // Existing record. 154 $update = array($key); 155 } 156 else { 157 // New record. 158 $update = array(); 159 $object->export_type = EXPORT_IN_DATABASE; 160 } 161 return drupal_write_record($table, $object, $update); 162 } 163 } 164 165 /** 166 * Delete a single exportable object. 167 * 168 * This only deletes from the database, which means that if an item is in 169 * code, then this is actually a revert. 170 * 171 * @param $table 172 * The name of the table to use to retrieve $schema values. This table 173 * must have an 'export' section containing data or this function 174 * will fail. 175 * @param $object 176 * The fully populated object to delete, or the export key. 177 */ 178 function ctools_export_crud_delete($table, $object) { 179 $schema = ctools_export_get_schema($table); 180 $export = $schema['export']; 181 182 if (!empty($export['delete callback']) && function_exists($export['delete callback'])) { 183 return $export['delete callback']($object); 184 } 185 else { 186 // If we were sent an object, get the export key from it. Otherwise 187 // assume we were sent the export key. 188 $value = is_object($object) ? $object->{$export['key']} : $object; 189 db_query("DELETE FROM {" . $table . "} WHERE " . $export['key'] . " = '%s'", $value); 190 } 191 } 192 193 /** 194 * Get the exported code of a single exportable object. 195 * 196 * @param $table 197 * The name of the table to use to retrieve $schema values. This table 198 * must have an 'export' section containing data or this function 199 * will fail. 200 * @param $object 201 * The fully populated object to delete, or the export key. 202 * @param $indent 203 * Any indentation to apply to the code, in case this object is embedded 204 * into another, for example. 205 * 206 * @return 207 * A string containing the executable export of the object. 208 */ 209 function ctools_export_crud_export($table, $object, $indent = '') { 210 $schema = ctools_export_get_schema($table); 211 $export = $schema['export']; 212 213 if (!empty($export['export callback']) && function_exists($export['export callback'])) { 214 return $export['export callback']($object, $indent); 215 } 216 else { 217 return ctools_export_object($table, $object, $indent); 218 } 219 } 220 221 /** 222 * Turn exported code into an object. 223 * 224 * Note: If the code is poorly formed, this could crash and there is no 225 * way to prevent this. 226 * 227 * @param $table 228 * The name of the table to use to retrieve $schema values. This table 229 * must have an 'export' section containing data or this function 230 * will fail. 231 * @param $code 232 * The code to eval to create the object. 233 * 234 * @return 235 * An object created from the export. This object will NOT have been saved 236 * to the database. In the case of failure, a string containing all errors 237 * that the system was able to determine. 238 */ 239 function ctools_export_crud_import($table, $code) { 240 $schema = ctools_export_get_schema($table); 241 $export = $schema['export']; 242 243 if (!empty($export['import callback']) && function_exists($export['import callback'])) { 244 return $export['import callback']($code); 245 } 246 else { 247 ob_start(); 248 eval($code); 249 ob_end_clean(); 250 251 if (empty(${$export['identifier']})) { 252 $errors = ob_get_contents(); 253 if (empty($errors)) { 254 $errors = t('No item found.'); 255 } 256 return $errors; 257 } 258 259 $item = ${$export['identifier']}; 260 261 // Set these defaults just the same way that ctools_export_new_object sets 262 // them. 263 $item->export_type = NULL; 264 $item->type = t('Local'); 265 266 return $item; 267 } 268 } 269 270 /** 271 * @} 272 */ 273 274 /** 275 * Load some number of exportable objects. 276 * 277 * This function will cache the objects, load subsidiary objects if necessary, 278 * check default objects in code and properly set them up. It will cache 279 * the results so that multiple calls to load the same objects 280 * will not cause problems. 281 * 282 * It attempts to reduce, as much as possible, the number of queries 283 * involved. 284 * 285 * @param $table 286 * The name of the table to be loaded from. Data is expected to be in the 287 * schema to make all this work. 288 * @param $type 289 * A string to notify the loader what the argument is 290 * - all: load all items. This is the default. $args is unused. 291 * - names: $args will be an array of specific named objects to load. 292 * - conditions: $args will be a keyed array of conditions. The conditions 293 * must be in the schema for this table or errors will result. 294 * @param $args 295 * An array of arguments whose actual use is defined by the $type argument. 296 */ 297 function ctools_export_load_object($table, $type = 'all', $args = array()) { 298 $cache = &ctools_static(__FUNCTION__); 299 $cached_database = &ctools_static('ctools_export_load_object_all'); 300 301 $schema = ctools_export_get_schema($table); 302 if (empty($schema)) { 303 return array(); 304 } 305 306 $join_schemas = array(); 307 $export = $schema['export']; 308 309 if (!isset($cache[$table])) { 310 $cache[$table] = array(); 311 } 312 313 // If fetching all and cached all, we've done so and we are finished. 314 if ($type == 'all' && !empty($cached_database[$table])) { 315 return $cache[$table]; 316 } 317 318 $return = array(); 319 320 // Don't load anything we've already cached. 321 if ($type == 'names' && !empty($args)) { 322 foreach ($args as $id => $name) { 323 if (isset($cache[$table][$name])) { 324 $return[$name] = $cache[$table][$name]; 325 unset($args[$id]); 326 } 327 } 328 329 // If nothing left to load, return the result. 330 if (empty($args)) { 331 return $return; 332 } 333 } 334 335 // Build the query 336 $query = "SELECT * FROM {" . $table . "} t__0"; 337 $alias_count = 1; 338 if (!empty($schema['join'])) { 339 foreach ($schema['join'] as $join_key => $join) { 340 $join_schema = drupal_get_schema($join['table']); 341 if (!empty($join_schema)) { 342 $query .= ' INNER JOIN {' . $join['table'] . '} t__' . $alias_count . ' ON t__0.' . $join['left_key'] . ' = ' . 't__' . $alias_count . '.' . $join['right_key']; 343 $alias_count++; 344 $join_schemas[$join['table']] = $join_schema; 345 if (!empty($join['extra'])) { 346 $query .= ' ' . $join['extra']; 347 } 348 } 349 } 350 } 351 352 $conditions = array(); 353 $query_args = array(); 354 355 // If they passed in names, add them to the query. 356 if ($type == 'names') { 357 if (!isset($export['key in table'])) { 358 $conditions[] = "$export[key] IN (" . db_placeholders($args, $schema['fields'][$export['key']]['type']) . ")"; 359 } 360 else { 361 $conditions[] = "$export[key] IN (" . db_placeholders($args, $join_schemas[$export['key in table']]['fields'][$export['key']]['type']) . ")"; 362 } 363 $query_args = $args; 364 } 365 else if ($type == 'conditions') { 366 foreach ($args as $key => $value) { 367 if (isset($schema['fields'][$key])) { 368 $conditions[] = "$key = " . db_type_placeholder($schema['fields'][$key]['type']); 369 $query_args[] = $value; 370 } 371 } 372 } 373 374 // Make a string out of the conditions. 375 if ($conditions) { 376 $query .= " WHERE " . implode(' AND ', $conditions); 377 } 378 379 $result = db_query($query, $query_args); 380 381 $status = variable_get($export['status'], array()); 382 // Unpack the results of the query onto objects and cache them. 383 while ($data = db_fetch_object($result)) { 384 $object = _ctools_export_unpack_object($schema, $data, $export['object']); 385 $object->table = $table; 386 $object->type = t('Normal'); 387 $object->export_type = EXPORT_IN_DATABASE; 388 // Determine if default object is enabled or disabled. 389 if (isset($status[$object->{$export['key']}])) { 390 $object->disabled = $status[$object->{$export['key']}]; 391 } 392 393 $cache[$table][$object->{$export['key']}] = $object; 394 if ($type == 'conditions') { 395 $return[$object->{$export['key']}] = $object; 396 } 397 } 398 399 // @todo Load subrecords. 400 401 if ($defaults = _ctools_export_get_defaults($table, $export)) { 402 403 foreach ($defaults as $object) { 404 if ($type == 'conditions') { 405 // if this does not match all of our conditions, skip it. 406 foreach ($args as $key => $value) { 407 if (!isset($object->$key) || $object->$key != $value) { 408 continue 2; 409 } 410 } 411 } 412 else if ($type == 'names') { 413 if (!in_array($object->{$export['key']}, $args)) { 414 continue; 415 } 416 } 417 418 // Determine if default object is enabled or disabled. 419 if (isset($status[$object->{$export['key']}])) { 420 $object->disabled = $status[$object->{$export['key']}]; 421 } 422 423 if (!empty($cache[$table][$object->{$export['key']}])) { 424 $cache[$table][$object->{$export['key']}]->type = t('Overridden'); 425 $cache[$table][$object->{$export['key']}]->export_type |= EXPORT_IN_CODE; 426 if ($type == 'conditions') { 427 $return[$object->{$export['key']}] = $cache[$table][$object->{$export['key']}]; 428 } 429 } 430 else { 431 $object->type = t('Default'); 432 $object->export_type = EXPORT_IN_CODE; 433 $object->in_code_only = TRUE; 434 $object->table = $table; 435 436 $cache[$table][$object->{$export['key']}] = $object; 437 if ($type == 'conditions') { 438 $return[$object->{$export['key']}] = $object; 439 } 440 } 441 } 442 } 443 444 // If fetching all, we've done so and we are finished. 445 if ($type == 'all') { 446 $cached_database[$table] = TRUE; 447 return $cache[$table]; 448 } 449 450 if ($type == 'names') { 451 foreach ($args as $name) { 452 if (isset($cache[$table][$name])) { 453 $return[$name] = $cache[$table][$name]; 454 } 455 } 456 } 457 458 // For conditions, 459 return $return; 460 } 461 462 /** 463 * Reset all static caches in ctools_export_load_object() or static caches for 464 * a given table in ctools_export_load_object(). 465 * 466 * @param $table 467 * String that is the name of a table. If not defined, all static caches in 468 * ctools_export_load_object() will be reset. 469 */ 470 function ctools_export_load_object_reset($table = NULL) { 471 if (empty($table)) { 472 ctools_static_reset('ctools_export_load_object'); 473 ctools_static_reset('ctools_export_load_object_all'); 474 ctools_static_reset('_ctools_export_get_defaults'); 475 ctools_static_reset('ctools_plugin_api_info'); 476 } 477 else { 478 $cache = &ctools_static('ctools_export_load_object'); 479 $cached_database = &ctools_static('ctools_export_load_object_all'); 480 $cached_defaults = &ctools_static('_ctools_export_get_defaults'); 481 unset($cache[$table]); 482 unset($cached_database[$table]); 483 unset($cached_defaults[$table]); 484 ctools_static_reset('ctools_plugin_api_info'); 485 } 486 } 487 488 /** 489 * Get the default version of an object, if it exists. 490 * 491 * This function doesn't care if an object is in the database or not and 492 * does not check. This means that export_type could appear to be incorrect, 493 * because a version could exist in the database. However, it's not 494 * incorrect for this function as it is *only* used for the default 495 * in code version. 496 */ 497 function ctools_get_default_object($table, $name) { 498 $schema = ctools_export_get_schema($table); 499 $export = $schema['export']; 500 501 if (!$export['default hook']) { 502 return; 503 } 504 505 // @todo add a method to load .inc files for this. 506 $defaults = _ctools_export_get_defaults($table, $export); 507 $status = variable_get($export['status'], array()); 508 509 if (!isset($defaults[$name])) { 510 return; 511 } 512 513 $object = $defaults[$name]; 514 515 // Determine if default object is enabled or disabled. 516 if (isset($status[$object->{$export['key']}])) { 517 $object->disabled = $status[$object->{$export['key']}]; 518 } 519 520 $object->type = t('Default'); 521 $object->export_type = EXPORT_IN_CODE; 522 $object->in_code_only = TRUE; 523 524 return $object; 525 } 526 527 /** 528 * Call the hook to get all default objects of the given type from the 529 * export. If configured properly, this could include loading up an API 530 * to get default objects. 531 */ 532 function _ctools_export_get_defaults($table, $export) { 533 $cache = &ctools_static(__FUNCTION__, array()); 534 535 if (!isset($cache[$table])) { 536 $cache[$table] = array(); 537 538 if ($export['default hook']) { 539 if (!empty($export['api'])) { 540 ctools_include('plugins'); 541 $info = ctools_plugin_api_include($export['api']['owner'], $export['api']['api'], 542 $export['api']['minimum_version'], $export['api']['current_version']); 543 $modules = array_keys($info); 544 } 545 else { 546 $modules = module_implements($export['default hook']); 547 } 548 549 foreach ($modules as $module) { 550 $function = $module . '_' . $export['default hook']; 551 if (function_exists($function)) { 552 foreach ((array) $function($export) as $name => $object) { 553 // Record the module that provides this exportable. 554 $object->export_module = $module; 555 556 if (empty($export['api'])) { 557 $cache[$table][$name] = $object; 558 } 559 else { 560 // If version checking is enabled, ensure that the object can be used. 561 if (isset($object->api_version) && 562 $object->api_version >= $export['api']['minimum_version'] && 563 $object->api_version <= $export['api']['current_version']) { 564 $cache[$table][$name] = $object; 565 } 566 } 567 } 568 } 569 } 570 571 drupal_alter($export['default hook'], $cache[$table]); 572 } 573 } 574 575 return $cache[$table]; 576 } 577 578 /** 579 * Unpack data loaded from the database onto an object. 580 * 581 * @param $schema 582 * The schema from drupal_get_schema(). 583 * @param $data 584 * The data as loaded by db_fetch_object(). 585 * @param $object 586 * If an object, data will be unpacked onto it. If a string 587 * an object of that type will be created. 588 */ 589 function _ctools_export_unpack_object($schema, $data, $object = 'stdClass') { 590 if (is_string($object)) { 591 if (class_exists($object)) { 592 $object = new $object; 593 } 594 else { 595 $object = new stdClass; 596 } 597 } 598 599 // Go through our schema and build correlations. 600 foreach ($schema['fields'] as $field => $info) { 601 $object->$field = empty($info['serialize']) ? $data->$field : unserialize(db_decode_blob($data->$field)); 602 } 603 604 if (isset($schema['join'])) { 605 foreach ($schema['join'] as $join_key => $join) { 606 $join_schema = ctools_export_get_schema($join['table']); 607 if (!empty($join['load'])) { 608 foreach ($join['load'] as $field) { 609 $info = $join_schema['fields'][$field]; 610 $object->$field = empty($info['serialize']) ? $data->$field : unserialize(db_decode_blob($data->$field)); 611 } 612 } 613 } 614 } 615 616 return $object; 617 } 618 619 /** 620 * Unpack data loaded from the database onto an object. 621 * 622 * @param $table 623 * The name of the table this object represents. 624 * @param $data 625 * The data as loaded by db_fetch_object(). 626 */ 627 function ctools_export_unpack_object($table, $data) { 628 $schema = ctools_export_get_schema($table); 629 return _ctools_export_unpack_object($schema, $data, $schema['export']['object']); 630 } 631 632 /** 633 * Export a field. 634 * 635 * This is a replacement for var_export(), allowing us to more nicely 636 * format exports. It will recurse down into arrays and will try to 637 * properly export bools when it can, though PHP has a hard time with 638 * this since they often end up as strings or ints. 639 */ 640 function ctools_var_export($var, $prefix = '') { 641 if (is_array($var)) { 642 if (empty($var)) { 643 $output = 'array()'; 644 } 645 else { 646 $output = "array(\n"; 647 foreach ($var as $key => $value) { 648 $output .= $prefix . " " . ctools_var_export($key) . " => " . ctools_var_export($value, $prefix . ' ') . ",\n"; 649 } 650 $output .= $prefix . ')'; 651 } 652 } 653 else if (is_object($var) && get_class($var) === 'stdClass') { 654 // var_export() will export stdClass objects using an undefined 655 // magic method __set_state() leaving the export broken. This 656 // workaround avoids this by casting the object as an array for 657 // export and casting it back to an object when evaluated. 658 $output .= '(object) ' . ctools_var_export((array) $var); 659 } 660 else if (is_bool($var)) { 661 $output = $var ? 'TRUE' : 'FALSE'; 662 } 663 else { 664 $output = var_export($var, TRUE); 665 } 666 667 return $output; 668 } 669 670 /** 671 * Export an object into code. 672 */ 673 function ctools_export_object($table, $object, $indent = '', $identifier = NULL, $additions = array(), $additions2 = array()) { 674 $schema = ctools_export_get_schema($table); 675 if (!isset($identifier)) { 676 $identifier = $schema['export']['identifier']; 677 } 678 679 $output = $indent . '$' . $identifier . ' = new ' . get_class($object) . ";\n"; 680 681 if ($schema['export']['can disable']) { 682 $output .= $indent . '$' . $identifier . '->disabled = FALSE; /* Edit this to true to make a default ' . $identifier . ' disabled initially */' . "\n"; 683 } 684 if (!empty($schema['export']['api']['current_version'])) { 685 $output .= $indent . '$' . $identifier . '->api_version = ' . $schema['export']['api']['current_version'] . ";\n"; 686 } 687 688 // Put top additions here: 689 foreach ($additions as $field => $value) { 690 $output .= $indent . '$' . $identifier . '->' . $field . ' = ' . ctools_var_export($value, $indent) . ";\n"; 691 } 692 693 $fields = $schema['fields']; 694 if (!empty($schema['join'])) { 695 foreach ($schema['join'] as $join) { 696 if (!empty($join['load'])) { 697 foreach ($join['load'] as $join_field) { 698 $fields[$join_field] = $join['fields'][$join_field]; 699 } 700 } 701 } 702 } 703 704 // Go through our schema and joined tables and build correlations. 705 foreach ($fields as $field => $info) { 706 if (!empty($info['no export'])) { 707 continue; 708 } 709 if (!isset($object->$field)) { 710 if (isset($info['default'])) { 711 $object->$field = $info['default']; 712 } 713 else { 714 $object->$field = ''; 715 } 716 } 717 718 // Note: This is the *field* export callback, not the table one! 719 if (!empty($info['export callback']) && function_exists($info['export callback'])) { 720 $output .= $indent . '$' . $identifier . '->' . $field . ' = ' . $info['export callback']($object, $field, $value, $indent) . ";\n"; 721 } 722 else { 723 $value = $object->$field; 724 if ($info['type'] == 'int') { 725 $value = (isset($info['size']) && $info['size'] == 'tiny') ? (bool) $value : (int) $value; 726 } 727 728 $output .= $indent . '$' . $identifier . '->' . $field . ' = ' . ctools_var_export($value, $indent) . ";\n"; 729 } 730 } 731 732 // And bottom additions here 733 foreach ($additions2 as $field => $value) { 734 $output .= $indent . '$' . $identifier . '->' . $field . ' = ' . ctools_var_export($value, $indent) . ";\n"; 735 } 736 737 return $output; 738 } 739 740 /** 741 * Get the schema for a given table. 742 * 743 * This looks for data the export subsystem needs and applies defaults so 744 * that it's easily available. 745 */ 746 function ctools_export_get_schema($table) { 747 $cache = &ctools_static(__FUNCTION__); 748 if (empty($cache[$table])) { 749 $schema = drupal_get_schema($table); 750 751 if (!isset($schema['export'])) { 752 return array(); 753 } 754 755 if (empty($schema['module'])) { 756 return array(); 757 } 758 759 // Add some defaults 760 $schema['export'] += array( 761 'key' => 'name', 762 'key name' => 'Name', 763 'object' => 'stdClass', 764 'status' => 'default_' . $table, 765 'default hook' => 'default_' . $table, 766 'can disable' => TRUE, 767 'identifier' => $table, 768 'primary key' => !empty($schema['primary key']) ? $schema['primary key'][0] : '', 769 'bulk export' => TRUE, 770 'list callback' => "$schema[module]_{$table}_list", 771 'to hook code callback' => "$schema[module]_{$table}_to_hook_code", 772 ); 773 774 // If the export definition doesn't have the "primary key" then the CRUD 775 // save callback won't work. 776 if (empty($schema['export']['primary key']) && user_access('administer site configuration')) { 777 drupal_set_message(t('The export definition of @table is missing the "primary key" property.', array('@table' => $table)), 'error'); 778 } 779 780 // Notes: 781 // The following callbacks may be defined to override default behavior 782 // when using CRUD functions: 783 // 784 // create callback 785 // load callback 786 // load all callback 787 // save callback 788 // delete callback 789 // export callback 790 // import callback 791 // 792 // See the appropriate ctools_export_crud function for details on what 793 // arguments these callbacks should accept. Please do not call these 794 // directly, always use the ctools_export_crud_* wrappers to ensure 795 // that default implementations are honored. 796 $cache[$table] = $schema; 797 } 798 799 return $cache[$table]; 800 } 801 802 /** 803 * Gets the schemas for all tables with ctools object metadata. 804 */ 805 function ctools_export_get_schemas($for_export = FALSE) { 806 static $export_tables; 807 if (is_null($export_tables)) { 808 $export_tables = array(); 809 $schemas = drupal_get_schema(); 810 foreach ($schemas as $table => $schema) { 811 if (!isset($schema['export'])) { 812 unset($schemas[$table]); 813 continue; 814 } 815 $export_tables[$table] = ctools_export_get_schema($table); 816 } 817 } 818 return $for_export ? array_filter($export_tables, '_ctools_export_filter_export_tables') : $export_tables; 819 } 820 821 function _ctools_export_filter_export_tables($schema) { 822 return !empty($schema['export']['bulk export']); 823 } 824 825 function ctools_export_get_schemas_by_module($modules = array(), $for_export = FALSE) { 826 $export_tables = array(); 827 $list = ctools_export_get_schemas($for_export); 828 foreach ($list as $table => $schema) { 829 $export_tables[$schema['module']][$table] = $schema; 830 } 831 return empty($modules) ? $export_tables : array_keys($export_tables, $modules); 832 } 833 834 /** 835 * Set the status of a default $object as a variable. 836 * 837 * The status, in this case, is whether or not it is 'disabled'. 838 * This function does not check to make sure $object actually 839 * exists. 840 */ 841 function ctools_export_set_status($table, $name, $new_status = TRUE) { 842 $schema = ctools_export_get_schema($table); 843 $status = variable_get($schema['export']['status'], array()); 844 845 $status[$name] = $new_status; 846 variable_set($schema['export']['status'], $status); 847 } 848 849 /** 850 * Set the status of a default $object as a variable. 851 * 852 * This is more efficient than ctools_export_set_status because it 853 * will actually unset the variable entirely if it's not necessary, 854 * this saving a bit of space. 855 */ 856 function ctools_export_set_object_status($object, $new_status = TRUE) { 857 $table = $object->table; 858 $schema = ctools_export_get_schema($table); 859 $export = $schema['export']; 860 $status = variable_get($schema['export']['status'], array()); 861 862 // Compare 863 if (!$new_status && $object->export_type & EXPORT_IN_DATABASE) { 864 unset($status[$object->{$export['key']}]); 865 } 866 else { 867 $status[$object->{$export['key']}] = $new_status; 868 } 869 870 variable_set($schema['export']['status'], $status); 871 } 872 873 /** 874 * Provide a form for displaying an export. 875 * 876 * This is a simple form that should be invoked like this: 877 * @code 878 * $output = drupal_get_form('ctools_export_form', $code, $object_title); 879 * @endcode 880 */ 881 function ctools_export_form(&$form_state, $code, $title = '') { 882 $lines = substr_count($code, "\n"); 883 $form['code'] = array( 884 '#type' => 'textarea', 885 '#title' => $title, 886 '#default_value' => $code, 887 '#rows' => $lines, 888 ); 889 890 return $form; 891 } 892 893 /** 894 * Create a new object based upon schema values. 895 * 896 * Because 'default' has ambiguous meaning on some fields, we will actually 897 * use 'object default' to fill in default values if default is not set 898 * That's a little safer to use as it won't cause weird database default 899 * situations. 900 */ 901 function ctools_export_new_object($table, $set_defaults = TRUE) { 902 $schema = ctools_export_get_schema($table); 903 $export = $schema['export']; 904 905 $object = new $export['object']; 906 foreach ($schema['fields'] as $field => $info) { 907 if (isset($info['object default'])) { 908 $object->$field = $info['object default']; 909 } 910 else if (isset($info['default'])) { 911 $object->$field = $info['default']; 912 } 913 else { 914 $object->$field = NULL; 915 } 916 } 917 918 if ($set_defaults) { 919 // Set some defaults so this data always exists. 920 // We don't set the export_type property here, as this object is not saved 921 // yet. We do give it NULL so we don't generate notices trying to read it. 922 $object->export_type = NULL; 923 $object->type = t('Local'); 924 } 925 return $object; 926 } 927 928 /** 929 * Convert a group of objects to code based upon input and return this as a larger 930 * export. 931 */ 932 function ctools_export_to_hook_code(&$code, $table, $names = array(), $name = 'foo') { 933 $schema = ctools_export_get_schema($table); 934 $export = $schema['export']; 935 // Use the schema-specified function for generating hook code, if one exists 936 if (function_exists($export['to hook code callback'])) { 937 $output = $export['to hook code callback']($names, $name); 938 } 939 // Otherwise, the following code generates basic hook code 940 else { 941 $output = ctools_export_default_to_hook_code($schema, $table, $names, $name); 942 } 943 944 if (!empty($output)) { 945 if (isset($export['api'])) { 946 if (isset($code[$export['api']['owner']][$export['api']['api']]['version'])) { 947 $code[$export['api']['owner']][$export['api']['api']]['version'] = max($code[$export['api']['owner']][$export['api']['api']]['version'], $export['api']['minimum_version']); 948 } 949 else { 950 $code[$export['api']['owner']][$export['api']['api']]['version'] = $export['api']['minimum_version']; 951 $code[$export['api']['owner']][$export['api']['api']]['code'] = ''; 952 } 953 $code[$export['api']['owner']][$export['api']['api']]['code'] .= $output; 954 } 955 else { 956 if (empty($code['general'])) { 957 $code['general'] = ''; 958 } 959 $code['general'] .= $output; 960 } 961 } 962 } 963 964 /** 965 * Default function to export objects to code. 966 * 967 * Note that if your module provides a 'to hook code callback' then it will 968 * receive only $names and $name as arguments. Your module is presumed to 969 * already know the rest. 970 */ 971 function ctools_export_default_to_hook_code($schema, $table, $names, $name) { 972 $export = $schema['export']; 973 $output = ''; 974 $objects = ctools_export_load_object($table, 'names', $names); 975 if ($objects) { 976 $output = "/**\n"; 977 $output .= " * Implementation of hook_{$export['default hook']}()\n"; 978 $output .= " */\n"; 979 $output .= "function " . $name . "_{$export['default hook']}() {\n"; 980 $output .= " \${$export['identifier']}s = array();\n\n"; 981 foreach ($objects as $object) { 982 $output .= ctools_export_crud_export($table, $object, ' '); 983 $output .= " \${$export['identifier']}s['" . check_plain($object->$export['key']) . "'] = \${$export['identifier']};\n\n"; 984 } 985 $output .= " return \${$export['identifier']}s;\n"; 986 $output .= "}\n"; 987 } 988 989 return $output; 990 } 991 /** 992 * Default function for listing bulk exportable objects. 993 */ 994 function ctools_export_default_list($table, $schema) { 995 $list = array(); 996 997 $items = ctools_export_crud_load_all($table); 998 $export_key = $schema['export']['key']; 999 1000 foreach ($items as $item) { 1001 // Try a couple of possible obvious title keys: 1002 if (!empty($item->admin_title)) { 1003 $string = "$item->admin_title (" . $item->$export_key . ")"; 1004 } 1005 elseif (!empty($item->title)) { 1006 $string = "$item->title (" . $item->$export_key . ")"; 1007 } 1008 else { 1009 $string = $item->$export_key; 1010 } 1011 $list[$item->$export_key] = check_plain($string); 1012 } 1013 return $list; 1014 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |