| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
1 <?php 2 // $Id: features.export.inc,v 1.1.2.62 2010/08/11 19:49:05 yhahn Exp $ 3 4 /** 5 * @param $items 6 * @param $module_name 7 * @return 8 */ 9 function features_populate($items, $dependencies, $module_name) { 10 // Sanitize items. 11 $items = array_filter($items); 12 $items['dependencies'] = drupal_map_assoc(array_filter($dependencies)); 13 14 // Populate stub 15 $stub = array('features' => array(), 'dependencies' => array(), 'conflicts' => array()); 16 $export = _features_populate($items, $stub, $module_name); 17 18 // Allow other modules to alter the export. 19 drupal_alter('features_export', $export, $module_name); 20 21 // Clean up and standardize order 22 foreach (array_keys($export['features']) as $k) { 23 ksort($export['features'][$k]); 24 } 25 ksort($export['features']); 26 ksort($export['dependencies']); 27 28 return $export; 29 } 30 31 /** 32 * Iterate and descend into a feature definition to extract module 33 * dependencies and feature definition. Calls hook_features_export for modules 34 * that implement it. 35 * 36 * @param $pipe 37 * Associative of array of module => info-for-module 38 * @param $export 39 * Associative array of items, and module dependencies which define a feature. 40 * Passed by reference. 41 * 42 * @return fully populated $export array. 43 */ 44 function _features_populate($pipe, &$export, $module_name = '') { 45 features_include(); 46 foreach ($pipe as $component => $data) { 47 if (features_hook($component, 'features_export')) { 48 // Pass module-specific data and export array. 49 // We don't use features_invoke() here since we need to pass $export by reference. 50 $function = "{$component}_features_export"; 51 $more = $function($data, $export, $module_name); 52 // Allow other modules to manipulate the pipe to add in additional modules. 53 drupal_alter('features_pipe_' . $component, $more, $data, $export, $module_name); 54 // Allow for export functions to request additional exports. 55 if (!empty($more)) { 56 _features_populate($more, $export, $module_name); 57 } 58 } 59 } 60 return $export; 61 } 62 63 /** 64 * Iterates over a list of dependencies and kills modules that are 65 * captured by other modules 'higher up'. 66 */ 67 function _features_export_minimize_dependencies($dependencies, $module_name = '') { 68 // Ensure that the module doesn't depend upon itself 69 if (!empty($module_name) && !empty($dependencies[$module_name])) { 70 unset($dependencies[$module_name]); 71 } 72 73 // Do some cleanup: 74 // - Remove modules required by Drupal core. 75 // - Protect against direct circular dependencies. 76 // - Remove "intermediate" dependencies. 77 $required = drupal_required_modules(); 78 foreach ($dependencies as $k => $v) { 79 if (empty($v) || in_array($v, $required)) { 80 unset($dependencies[$k]); 81 } 82 else { 83 $module = features_get_modules($v); 84 if ($module && !empty($module->info['dependencies'])) { 85 // If this dependency depends on the module itself, we have a circular dependency. 86 // Don't let it happen. Only you can prevent forest fires. 87 if (in_array($module_name, $module->info['dependencies'])) { 88 unset($dependencies[$k]); 89 } 90 // Iterate through the dependency's dependencies and remove any dependencies 91 // that are captured by it. 92 else { 93 foreach ($module->info['dependencies'] as $j => $dependency) { 94 if (array_search($dependency, $dependencies) !== FALSE) { 95 $position = array_search($dependency, $dependencies); 96 unset($dependencies[$position]); 97 } 98 } 99 } 100 } 101 } 102 } 103 return drupal_map_assoc(array_unique($dependencies)); 104 } 105 106 /** 107 * Iterates over a list of dependencies and maximize the list of modules. 108 */ 109 function _features_export_maximize_dependencies($dependencies, $module_name = '', $first = TRUE) { 110 $maximized = $dependencies; 111 foreach ($dependencies as $k => $v) { 112 $module = features_get_modules($v); 113 if ($module && !empty($module->info['dependencies'])) { 114 $maximized = array_merge($maximized, _features_export_maximize_dependencies($module->info['dependencies'], $module_name, FALSE)); 115 } 116 } 117 return array_unique($maximized); 118 } 119 120 /** 121 * Prepare a feature export array into a finalized info array. 122 */ 123 function features_export_prepare($export, $module_name, $reset = FALSE) { 124 $existing = features_get_modules($module_name, $reset); 125 126 // Prepare info string -- if module exists, merge into its existing info file 127 $defaults = $existing ? $existing->info : array('core' => '6.x', 'package' => 'Features'); 128 $export = array_merge($defaults, $export); 129 130 // Cleanup info array 131 foreach ($export['features'] as $component => $data) { 132 $export['features'][$component] = array_keys($data); 133 } 134 if (isset($export['dependencies'])) { 135 $export['dependencies'] = array_values($export['dependencies']); 136 } 137 if (isset($export['conflicts'])) { 138 unset($export['conflicts']); 139 } 140 ksort($export); 141 return $export; 142 } 143 144 /** 145 * Generate an array of hooks and their raw code. 146 */ 147 function features_export_render_hooks($export, $module_name, $reset = FALSE) { 148 features_include(); 149 $code = array(); 150 151 // Sort components to keep exported code consistent 152 ksort($export['features']); 153 154 foreach ($export['features'] as $component => $data) { 155 if (!empty($data)) { 156 // Sort the items so that we don't generate different exports based on order 157 asort($data); 158 if (features_hook($component, 'features_export_render')) { 159 $hooks = features_invoke($component, 'features_export_render', $module_name, $data, $export); 160 $code[$component] = $hooks; 161 } 162 } 163 } 164 return $code; 165 } 166 167 /** 168 * Render feature export into an array representing its files. 169 * 170 * @param $export 171 * An exported feature definition. 172 * @param $module_name 173 * The name of the module to be exported. 174 * @param $reset 175 * Boolean flag for resetting the module cache. Only set to true when 176 * doing a final export for delivery. 177 * 178 * @return array of info file and module file contents. 179 */ 180 function features_export_render($export, $module_name, $reset = FALSE) { 181 $code = array(); 182 183 // Generate hook code 184 $component_hooks = features_export_render_hooks($export, $module_name, $reset); 185 $components = features_get_components(); 186 187 // Group component code into their respective files 188 foreach ($component_hooks as $component => $hooks) { 189 $file = array('name' => 'features'); 190 if (isset($components[$component]['default_file'])) { 191 switch ($components[$component]['default_file']) { 192 case FEATURES_DEFAULTS_INCLUDED: 193 $file['name'] = "features.$component"; 194 break; 195 case FEATURES_DEFAULTS_CUSTOM: 196 $file['name'] = $components[$component]['default_filename']; 197 break; 198 } 199 } 200 201 if (!isset($code[$file['name']])) { 202 $code[$file['name']] = array(); 203 } 204 205 foreach ($hooks as $hook_name => $hook_code) { 206 $code[$file['name']][$hook_name] = features_export_render_defaults($module_name, $hook_name, $hook_code); 207 } 208 } 209 210 // Finalize strings to be written to files 211 foreach ($code as $filename => $contents) { 212 $code[$filename] = "<?php\n\n". implode("\n\n", $contents) ."\n"; 213 } 214 215 // Generate info file output 216 $export = features_export_prepare($export, $module_name, $reset); 217 $code['info'] = features_export_info($export); 218 219 // Prepare the module 220 // If module exists, let it be and include it in the files 221 if ($existing = features_get_modules($module_name, TRUE)) { 222 $code['module'] = file_get_contents($existing->filename); 223 224 // If the current module file does not reference the features.inc include, 225 // set a warning message. 226 if (isset($code['features']) && strpos($code['module'], "{$module_name}.features.inc") === FALSE) { 227 features_log(t('@module does not appear to include the @include file.', array('@module' => "{$module_name}.module", '@include' => "{$module_name}.features.inc")), 'warning'); 228 } 229 230 // Deprecated files. Display a message for any of these files letting the 231 // user know that they may be removed. 232 $deprecated = array( 233 "{$module_name}.defaults", 234 "{$module_name}.features.views", 235 "{$module_name}.features.node" 236 ); 237 foreach (file_scan_directory(drupal_get_path('module', $module_name), '.*') as $file) { 238 if (in_array($file->name, $deprecated, TRUE)) { 239 features_log(t('The file @filename has been deprecated and can be removed.', array('@filename' => $file->basename)), 'status'); 240 } 241 elseif ($file->name === "{$module_name}.features" && empty($code['features'])) { 242 $code['features'] = "<?php\n\n// This file is deprecated and can be removed.\n// Please remove include_once('{$module_name}.features.inc') in {$module_name}.module as well.\n"; 243 } 244 } 245 } 246 // Add a stub module to include the defaults 247 else if (!empty($code['features'])) { 248 $code['module'] = "<?php\n\ninclude_once('{$module_name}.features.inc');\n"; 249 } 250 else { 251 $code['module'] = "<?php\n\n// Drupal needs this blank file.\n"; 252 } 253 return $code; 254 } 255 256 /** 257 * Detect differences between DB and code components of a feature. 258 */ 259 function features_detect_overrides($module) { 260 static $cache; 261 if (!isset($cache)) { 262 $cache = array(); 263 } 264 if (!isset($cache[$module->name])) { 265 // Rebuild feature from .info file description and prepare an export from current DB state. 266 $export = features_populate($module->info['features'], $module->info['dependencies'], $module->name); 267 $export = features_export_prepare($export, $module->name); 268 269 $overridden = array(); 270 271 // Compare feature info 272 _features_sanitize($module->info); 273 _features_sanitize($export); 274 275 $compare = array('normal' => features_export_info($export), 'default' => features_export_info($module->info)); 276 if ($compare['normal'] !== $compare['default']) { 277 $overridden['info'] = $compare; 278 } 279 280 // Collect differences at a per-component level 281 $states = features_get_component_states(array($module->name), FALSE); 282 foreach ($states[$module->name] as $component => $state) { 283 if ($state != FEATURES_DEFAULT) { 284 $normal = features_get_normal($component, $module->name); 285 $default = features_get_default($component, $module->name); 286 _features_sanitize($normal); 287 _features_sanitize($default); 288 289 $compare = array('normal' => features_var_export($normal), 'default' => features_var_export($default)); 290 if (_features_linetrim($compare['normal']) !== _features_linetrim($compare['default'])) { 291 $overridden[$component] = $compare; 292 } 293 } 294 } 295 $cache[$module->name] = $overridden; 296 } 297 return $cache[$module->name]; 298 } 299 300 /** 301 * Gets the available default hooks keyed by components. 302 */ 303 function features_get_default_hooks($component = NULL, $reset = FALSE) { 304 static $hooks; 305 if (!isset($hooks) || $reset) { 306 $hooks = array(); 307 features_include(); 308 foreach (module_implements('features_api') as $module) { 309 $info = module_invoke($module, 'features_api'); 310 foreach ($info as $k => $v) { 311 if (isset($v['default_hook'])) { 312 $hooks[$k] = $v['default_hook']; 313 } 314 } 315 } 316 } 317 if (isset($component)) { 318 return isset($hooks[$component]) ? $hooks[$component] : FALSE; 319 } 320 return $hooks; 321 } 322 323 /** 324 * Return a code string representing an implementation of a defaults module hook. 325 */ 326 function features_export_render_defaults($module, $hook, $code) { 327 $output = array(); 328 $output[] = "/**"; 329 $output[] = " * Implementation of hook_{$hook}()."; 330 $output[] = " */"; 331 $output[] = "function {$module}_{$hook}() {"; 332 $output[] = $code; 333 $output[] = "}"; 334 return implode("\n", $output); 335 } 336 337 /** 338 * Generate code friendly to the Drupal .info format from a structured array. 339 * 340 * @param $info 341 * An array or single value to put in a module's .info file. 342 * @param $parents 343 * Array of parent keys (internal use only). 344 * 345 * @return 346 * A code string ready to be written to a module's .info file. 347 */ 348 function features_export_info($info, $parents = array()) { 349 $output = ''; 350 if (is_array($info)) { 351 foreach ($info as $k => $v) { 352 $child = $parents; 353 $child[] = $k; 354 $output .= features_export_info($v, $child); 355 } 356 } 357 else if (!empty($info) && count($parents)) { 358 $line = array_shift($parents); 359 foreach ($parents as $key) { 360 $line .= is_numeric($key) ? "[]" : "[{$key}]"; 361 } 362 $line .= " = \"{$info}\"\n"; 363 return $line; 364 } 365 return $output; 366 } 367 368 /** 369 * Tar creation function. Written by dmitrig01. 370 * 371 * @param $name 372 * Filename of the file to be tarred. 373 * @param $contents 374 * String contents of the file. 375 * 376 * @return 377 * A string of the tar file contents. 378 */ 379 function features_tar_create($name, $contents) { 380 $tar = ''; 381 $binary_data_first = pack("a100a8a8a8a12A12", 382 $name, 383 '100644 ', // File permissions 384 ' 765 ', // UID, 385 ' 765 ', // GID, 386 sprintf("%11s ", decoct(strlen($contents))), // Filesize, 387 sprintf("%11s", decoct(time())) // Creation time 388 ); 389 $binary_data_last = pack("a1a100a6a2a32a32a8a8a155a12", '', '', '', '', '', '', '', '', '', ''); 390 391 $checksum = 0; 392 for ($i = 0; $i < 148; $i++) { 393 $checksum += ord(substr($binary_data_first, $i, 1)); 394 } 395 for ($i = 148; $i < 156; $i++) { 396 $checksum += ord(' '); 397 } 398 for ($i = 156, $j = 0; $i < 512; $i++, $j++) { 399 $checksum += ord(substr($binary_data_last, $j, 1)); 400 } 401 402 $tar .= $binary_data_first; 403 $tar .= pack("a8", sprintf("%6s ", decoct($checksum))); 404 $tar .= $binary_data_last; 405 406 $buffer = str_split($contents, 512); 407 foreach ($buffer as $item) { 408 $tar .= pack("a512", $item); 409 } 410 return $tar; 411 } 412 413 /** 414 * Export var function -- from Views. 415 */ 416 function features_var_export($var, $prefix = '', $init = TRUE) { 417 if (is_object($var)) { 418 $output = method_exists($var, 'export') ? $var->export() : features_var_export((array) $var); 419 } 420 else if (is_array($var)) { 421 if (empty($var)) { 422 $output = 'array()'; 423 } 424 else { 425 $output = "array(\n"; 426 foreach ($var as $key => $value) { 427 $output .= " '$key' => " . features_var_export($value, ' ', FALSE) . ",\n"; 428 } 429 $output .= ')'; 430 } 431 } 432 else if (is_bool($var)) { 433 $output = $var ? 'TRUE' : 'FALSE'; 434 } 435 else if (is_string($var) && strpos($var, "\n") !== FALSE) { 436 // Replace line breaks in strings with a token for replacement 437 // at the very end. This protects whitespace in strings from 438 // unintentional indentation. 439 $var = str_replace("\n", "***BREAK***", $var); 440 $output = var_export($var, TRUE); 441 } 442 else { 443 $output = var_export($var, TRUE); 444 } 445 446 if ($prefix) { 447 $output = str_replace("\n", "\n$prefix", $output); 448 } 449 450 if ($init) { 451 $output = str_replace("***BREAK***", "\n", $output); 452 } 453 454 return $output; 455 } 456 457 /** 458 * Helper function to return an array of t()'d translatables strings. 459 * Useful for providing a separate array of translatables with your 460 * export so that string extractors like potx can detect them. 461 */ 462 function features_translatables_export($translatables, $indent = '') { 463 $output = ''; 464 $translatables = array_filter(array_unique($translatables)); 465 if (!empty($translatables)) { 466 $output .= "{$indent}// Translatables\n"; 467 $output .= "{$indent}// Included for use with string extractors like potx.\n"; 468 sort($translatables); 469 foreach ($translatables as $string) { 470 $output .= "{$indent}t(" . features_var_export($string) . ");\n"; 471 } 472 } 473 return $output; 474 } 475 476 /** 477 * Get a summary storage state for a feature. 478 */ 479 function features_get_storage($module_name) { 480 // Get component states, and array_diff against array(FEATURES_DEFAULT). 481 // If the returned array has any states that don't match FEATURES_DEFAULT, 482 // return the highest state. 483 $states = features_get_component_states(array($module_name), FALSE); 484 $states = array_diff($states[$module_name], array(FEATURES_DEFAULT)); 485 $storage = !empty($states) ? max($states) : FEATURES_DEFAULT; 486 return $storage; 487 } 488 489 /** 490 * Wrapper around features_get_[storage] to return an md5hash of a normalized 491 * defaults/normal object array. Can be used to compare normal/default states 492 * of a module's component. 493 */ 494 function features_get_signature($state = 'default', $module_name, $component, $reset = FALSE) { 495 switch ($state) { 496 case 'cache': 497 $codecache = variable_get('features_codecache', array()); 498 return isset($codecache[$module_name][$component]) ? $codecache[$module_name][$component] : FALSE; 499 case 'default': 500 $objects = features_get_default($component, $module_name, TRUE, $reset); 501 break; 502 case 'normal': 503 $objects = features_get_normal($component, $module_name, $reset); 504 break; 505 } 506 if (!empty($objects)) { 507 $objects = (array) $objects; 508 _features_sanitize($objects); 509 return md5(_features_linetrim(features_var_export($objects))); 510 } 511 return FALSE; 512 } 513 514 /** 515 * Set the signature of a module/component pair in the codecache. 516 */ 517 function features_set_signature($module, $component, $signature = NULL) { 518 $var_codecache = variable_get('features_codecache', array()); 519 $signature = isset($signature) ? $signature : features_get_signature('default', $module, $component, TRUE); 520 $var_codecache[$module][$component] = $signature; 521 variable_set('features_codecache', $var_codecache); 522 } 523 524 /** 525 * Processing semaphore operations. 526 */ 527 function features_semaphore($op, $component) { 528 // Note: we don't use variable_get() here as the inited variable 529 // static cache may be stale. Retrieving directly from the DB narrows 530 // the possibility of collision. 531 $semaphore = db_result(db_query("SELECT value FROM {variable} WHERE name = 'features_semaphore'")); 532 $semaphore = !empty($semaphore) ? unserialize($semaphore) : array(); 533 534 switch ($op) { 535 case 'get': 536 return isset($semaphore[$component]) ? $semaphore[$component] : FALSE; 537 case 'set': 538 $semaphore[$component] = time(); 539 variable_set('features_semaphore', $semaphore); 540 break; 541 case 'del': 542 if (isset($semaphore[$component])) { 543 unset($semaphore[$component]); 544 variable_set('features_semaphore', $semaphore); 545 } 546 break; 547 } 548 } 549 550 /** 551 * Get normal objects for a given module/component pair. 552 */ 553 function features_get_normal($component, $module_name, $reset = FALSE) { 554 static $cache; 555 if (!isset($cache) || $reset) { 556 $cache = array(); 557 } 558 if (!isset($cache[$module_name][$component])) { 559 features_include(); 560 $code = NULL; 561 $module = features_get_features($module_name); 562 563 // Special handling for dependencies component. 564 if ($component === 'dependencies') { 565 $cache[$module_name][$component] = isset($module->info['dependencies']) ? array_filter($module->info['dependencies'], 'module_exists') : array(); 566 } 567 // All other components. 568 else { 569 $default_hook = features_get_default_hooks($component); 570 if ($module && $default_hook && isset($module->info['features'][$component]) && features_hook($component, 'features_export_render')) { 571 $code = features_invoke($component, 'features_export_render', $module_name, $module->info['features'][$component]); 572 $cache[$module_name][$component] = isset($code[$default_hook]) ? eval($code[$default_hook]) : FALSE; 573 } 574 } 575 576 // Clear out vars for memory's sake. 577 unset($code); 578 unset($module); 579 } 580 return isset($cache[$module_name][$component]) ? $cache[$module_name][$component] : FALSE; 581 } 582 583 /** 584 * Get defaults for a given module/component pair. 585 */ 586 function features_get_default($component, $module_name = NULL, $alter = TRUE, $reset = FALSE) { 587 static $cache = array(); 588 features_include(); 589 features_include_defaults($component); 590 $default_hook = features_get_default_hooks($component); 591 $components = features_get_components(); 592 593 // Collect defaults for all modules if no module name was specified. 594 if (isset($module_name)) { 595 $modules = array($module_name); 596 } 597 else { 598 $modules = ($component === 'dependencies') ? array_keys(features_get_features()) : module_implements($default_hook); 599 } 600 601 // Collect and cache information for each specified module. 602 foreach ($modules as $m) { 603 if (!isset($cache[$component][$m]) || $reset) { 604 // Special handling for dependencies component. 605 if ($component === 'dependencies') { 606 $module = features_get_features($m); 607 $cache[$component][$m] = isset($module->info['dependencies']) ? $module->info['dependencies'] : array(); 608 unset($module); 609 } 610 // All other components 611 else { 612 if ($default_hook && module_hook($m, $default_hook)) { 613 $cache[$component][$m] = module_invoke($m, $default_hook); 614 if ($alter) { 615 drupal_alter($default_hook, $cache[$component][$m]); 616 } 617 } 618 else { 619 $cache[$component][$m] = FALSE; 620 } 621 } 622 } 623 } 624 625 // A specific module was specified. Retrieve only its components. 626 if (isset($module_name)) { 627 return isset($cache[$component][$module_name]) ? $cache[$component][$module_name] : FALSE; 628 } 629 // No module was specified. Retrieve all components. 630 $all_defaults = array(); 631 if (isset($cache[$component])) { 632 foreach (array_filter($cache[$component]) as $module_components) { 633 $all_defaults = array_merge($all_defaults, $module_components); 634 } 635 } 636 return $all_defaults; 637 } 638 639 /** 640 * Get a map of components to their providing modules. 641 */ 642 function features_get_default_map($component, $attribute = NULL, $callback = NULL, $reset = FALSE) { 643 static $map = array(); 644 features_include(); 645 features_include_defaults($component); 646 if ((!isset($map[$component]) || $reset) && $default_hook = features_get_default_hooks($component)) { 647 $map[$component] = array(); 648 foreach (module_implements($default_hook) as $module) { 649 if ($defaults = features_get_default($component, $module)) { 650 foreach ($defaults as $key => $object) { 651 if (isset($callback)) { 652 if ($object_key = $callback($object)) { 653 $map[$component][$object_key] = $module; 654 } 655 } 656 elseif (isset($attribute)) { 657 if (is_object($object) && isset($object->{$attribute})) { 658 $map[$component][$object->{$attribute}] = $module; 659 } 660 elseif (is_array($object) && isset($object[$attribute])) { 661 $map[$component][$object[$attribute]] = $module; 662 } 663 } 664 elseif (!isset($attribute) && !isset($callback)) { 665 if (!is_numeric($key)) { 666 $map[$component][$key] = $module; 667 } 668 } 669 else { 670 return FALSE; 671 } 672 } 673 } 674 } 675 } 676 return isset($map[$component]) ? $map[$component] : FALSE; 677 } 678 679 /** 680 * Retrieve an array of features/components and their current states. 681 */ 682 function features_get_component_states($features = array(), $rebuild_only = TRUE, $reset = FALSE) { 683 static $cache; 684 if (!isset($cache) || $reset) { 685 $cache = array(); 686 } 687 688 $features = !empty($features) ? $features : array_keys(features_get_features()); 689 690 // Retrieve only rebuildable components if requested. 691 features_include(); 692 $components = array_keys(features_get_components()); 693 if ($rebuild_only) { 694 foreach ($components as $k => $component) { 695 if (!features_hook($component, 'features_rebuild')) { 696 unset($components[$k]); 697 } 698 } 699 } 700 701 foreach ($features as $feature) { 702 $cache[$feature] = isset($cache[$feature]) ? $cache[$feature] : array(); 703 if (module_exists($feature)) { 704 foreach ($components as $component) { 705 if (!isset($cache[$feature][$component])) { 706 $normal = features_get_signature('normal', $feature, $component, $reset); 707 $default = features_get_signature('default', $feature, $component, $reset); 708 $codecache = features_get_signature('cache', $feature, $component, $reset); 709 $semaphore = features_semaphore('get', $component); 710 711 // DB and code states match, there is nothing more to check. 712 if ($normal == $default) { 713 $cache[$feature][$component] = FEATURES_DEFAULT; 714 715 // Stale semaphores can be deleted. 716 features_semaphore('del', $component); 717 718 // Update code cache if it is stale, clear out semaphore if it stale. 719 if ($default != $codecache) { 720 features_set_signature($feature, $component, $default); 721 } 722 } 723 // Component properly implements exportables. 724 else if (!features_hook($component, 'features_rebuild')) { 725 $cache[$feature][$component] = FEATURES_OVERRIDDEN; 726 } 727 // Component does not implement exportables. 728 else { 729 if (empty($semaphore)) { 730 // Exception for dependencies. Dependencies are always rebuildable. 731 if ($component === 'dependencies') { 732 $cache[$feature][$component] = FEATURES_REBUILDABLE; 733 } 734 // All other rebuildable components require comparison. 735 else { 736 // Code has not changed, but DB does not match. User has DB overrides. 737 if ($codecache == $default) { 738 $cache[$feature][$component] = FEATURES_OVERRIDDEN; 739 } 740 // DB has no modifications to prior code state (or this is initial install). 741 else if ($codecache == $normal || empty($codecache)) { 742 $cache[$feature][$component] = FEATURES_REBUILDABLE; 743 } 744 // None of the states match. Requires user intervention. 745 else if ($codecache != $default) { 746 $cache[$feature][$component] = FEATURES_NEEDS_REVIEW; 747 } 748 } 749 } 750 else { 751 // Semaphore is still within processing horizon. Do nothing. 752 if ((time() - $semaphore) < FEATURES_SEMAPHORE_TIMEOUT) { 753 $cache[$feature][$component] = FEATURES_REBUILDING; 754 } 755 // A stale semaphore means a previous rebuild attempt did not complete. 756 // Attempt to complete the rebuild. 757 else { 758 $cache[$feature][$component] = FEATURES_REBUILDABLE; 759 } 760 } 761 } 762 } 763 } 764 } 765 } 766 767 // Filter cached components on the way out to ensure that even if we have 768 // cached more data than has been requested, the return value only reflects 769 // the requested features/components. 770 $return = $cache; 771 $return = array_intersect_key($return, array_flip($features)); 772 foreach ($return as $k => $v) { 773 $return[$k] = array_intersect_key($return[$k], array_flip($components)); 774 } 775 return $return; 776 } 777 778 /** 779 * Helper function to eliminate whitespace differences in code. 780 */ 781 function _features_linetrim($code) { 782 $code = explode("\n", $code); 783 foreach ($code as $k => $line) { 784 $code[$k] = trim($line); 785 } 786 return implode("\n", $code); 787 } 788 789 /** 790 * "Sanitizes" an array recursively, performing two key operations: 791 * - Sort an array by its keys (assoc) or values (non-assoc) 792 * - Remove any null or empty values for associative arrays (array_filter()). 793 */ 794 function _features_sanitize(&$array) { 795 if (is_array($array)) { 796 $is_assoc = (array_keys($array) != range(0, count($array) - 1)); 797 if ($is_assoc) { 798 ksort($array); 799 $array = array_filter($array); 800 } 801 else { 802 sort($array); 803 } 804 foreach ($array as $k => $v) { 805 if (is_array($v)) { 806 _features_sanitize($array[$k]); 807 } 808 } 809 } 810 }
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 |