| [ Index ] |
PHP Cross Reference of Drupal 6 (yi-drupal) |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * @file 5 * Module builder code generating code. 6 * 7 * Note that info file generating code happens in generate_info_VERSION, 8 * as it's version-specific. 9 */ 10 11 /** 12 * Generate info code. New OO version! 13 */ 14 function module_builder_generate_info_oo($module_data) { 15 $class = module_builder_get_class('info'); 16 $generator = new $class($module_data); 17 $code = $generator->build(); 18 19 return $code; 20 } 21 22 /** 23 * Helper function to get the desired class. 24 * 25 * @param $type 26 * One of (so far) 'info' or 'code'. 27 * @return 28 * A class name for the type and, if it exists, version, eg 'ModuleBuilderGeneratorInfo6'. 29 */ 30 function module_builder_get_class($type) { 31 $type = ucfirst($type); 32 $version = _module_builder_drupal_major_version(); 33 $class = 'ModuleBuilderGenerator' . $type . $version; 34 if (!class_exists($class)) { 35 $class = 'ModuleBuilderGenerator' . $type; 36 } 37 return $class; 38 } 39 40 /** 41 * Base class for code generators. 42 * 43 * TODO: much more of the code generation could be moved to OO code: 44 * - pass all hook data to one code generator object, representing the .module 45 * file, which then instantiates further objects for the other files needed. 46 * This would probably entail a controller object which can hold the list of 47 * current generators. 48 * - templates. 49 */ 50 abstract class ModuleBuilderGenerator { 51 function __construct($module_data) { 52 $this->module_data = $module_data; 53 } 54 55 /** 56 * The main code building function. 57 */ 58 function build() { 59 $output = ''; 60 $output .= $this->file_header(); 61 $output .= $this->code_header(); 62 $output .= $this->code_body(); 63 $output .= $this->code_footer(); 64 65 return $output; 66 } 67 68 69 /** 70 * Return the PHP file header line. 71 */ 72 function file_header() { 73 return "<?php\n"; 74 } 75 76 /** 77 * Return the file doxygen header and any custom header code. 78 */ 79 function code_header() { 80 $filename = $this->filename; 81 $default = <<<EOT 82 /** 83 * @file $filename 84 * TODO: Enter file description here. 85 */ 86 87 EOT; 88 $code = variable_get('module_builder_header', $default); 89 return $code; 90 } 91 92 /** 93 * Return the main body of the file code. 94 */ 95 abstract function code_body(); 96 97 /** 98 * Return a file footer. 99 */ 100 function code_footer() {} 101 } 102 103 /** 104 * Generator class for module code files. 105 */ 106 class ModuleBuilderGeneratorCode extends ModuleBuilderGenerator { 107 function __construct($module_data) { 108 $this->module_data = $module_data; 109 } 110 111 function code_body() { 112 // Get old style variable names. 113 $module_data = $this->module_data; 114 $hook_data = $this->hook_data; 115 $code = ''; 116 foreach ($hook_data as $hook_name => $hook) { 117 118 // Display PHP doc. 119 $code .= "\n" . module_builder_code_hook_doxy($hook_name); 120 121 // function declaration: put in the module name, add closing brace, decode html entities 122 $declaration = str_replace('hook', $module_data['module_root_name'], $hook['declaration']) . ' {'; 123 $code .= htmlspecialchars_decode($declaration); 124 125 126 // See if function bodies exist; if so, use function bodies from template 127 if (isset($hook['template'])) { 128 // Strip out INFO: comments for advanced users 129 if (!variable_get('module_builder_detail', 0)) { 130 // Used to strip INFO messages out of generated file for advanced users. 131 $pattern = '#\s+/\* INFO:(.*?)\*/#ms'; 132 $hook['template'] = preg_replace($pattern, '', $hook['template']); 133 } 134 //dsm($hook); 135 136 $code .= $hook['template']; 137 } 138 else { 139 $code .= "\n\n"; 140 } 141 $code .= "}\n\n"; 142 } // foreach hook 143 144 // Replace variables 145 $variables = array( 146 '%module' => $module_data['module_root_name'], 147 '%description' => str_replace("'", "\'", $module_data['module_short_description']), 148 '%name' => !empty($module_data['module_readable_name']) ? str_replace("'", "\'", $module_data['module_readable_name']) : $module_data['module_root_name'], 149 '%help' => !empty($module_data['module_help_text']) ? str_replace('"', '\"', $module_data['module_help_text']) : t('TODO: Create admin help text.'), 150 '%readable' => str_replace("'", "\'", $module_data['module_readable_name']), 151 ); 152 $code = strtr($code, $variables); 153 154 return $code; 155 } 156 157 /** 158 * Return a file footer. 159 */ 160 function code_footer() { 161 $footer = variable_get('module_builder_footer', ''); 162 return $footer; 163 } 164 } 165 166 /** 167 * Generator base class for module info file. 168 */ 169 class ModuleBuilderGeneratorInfo extends ModuleBuilderGenerator { 170 /** 171 * Override as info files have no header. 172 */ 173 function file_header() { } 174 175 /** 176 * Override as info files have no header. 177 */ 178 function code_header($filename = NULL) { 179 } 180 181 // Override abstract... 182 function code_body() {} 183 } 184 185 /** 186 * Generator class for module info file for Drupal 5. 187 */ 188 class ModuleBuilderGeneratorInfo5 extends ModuleBuilderGeneratorInfo { 189 function code_body() { 190 $module_data = $this->module_data; 191 192 $info .= 'name = ' . $module_data['module_readable_name'] . "\n"; 193 $info .= 'description = '. $module_data['module_short_description'] ."\n"; 194 195 if (!empty($module_data['module_dependencies'])) { 196 $info .= 'dependencies = '. $module_data['module_dependencies'] ."\n"; 197 } 198 199 if (!empty($module_data['module_package'])) { 200 $info .= 'package = '. $module_data['module_package'] ."\n"; 201 } 202 203 return $info; 204 } 205 } 206 207 /** 208 * Generator class for module info file for Drupal 6. 209 */ 210 class ModuleBuilderGeneratorInfo6 extends ModuleBuilderGeneratorInfo { 211 function code_body() { 212 $module_data = $this->module_data; 213 214 $info .= 'name = ' . $module_data['module_readable_name'] . "\n"; 215 $info .= 'description = '. $module_data['module_short_description'] ."\n"; 216 217 if (!empty($module_data['module_dependencies'])) { 218 foreach (explode(' ', $module_data['module_dependencies']) as $dep) { 219 $info .= 'dependencies[] = '. $dep ."\n"; 220 } 221 } 222 223 if (!empty($module_data['module_package'])) { 224 $info .= 'package = '. $module_data['module_package'] ."\n"; 225 } 226 $info .= "core = 6.x\n"; 227 228 return $info; 229 } 230 } 231 232 /** 233 * Generator class for module info file for Drupal 7. 234 */ 235 class ModuleBuilderGeneratorInfo7 extends ModuleBuilderGeneratorInfo { 236 function code_body() { 237 $module_data = $this->module_data; 238 //print_r($module_data); 239 240 $info .= 'name = ' . $module_data['module_readable_name'] . "\n"; 241 $info .= 'description = '. $module_data['module_short_description'] ."\n"; 242 243 if (!empty($module_data['module_dependencies'])) { 244 foreach (explode(' ', $module_data['module_dependencies']) as $dep) { 245 $info .= 'dependencies[] = '. $dep ."\n"; 246 } 247 } 248 249 if (!empty($module_data['module_package'])) { 250 $info .= 'package = '. $module_data['module_package'] ."\n"; 251 } 252 $info .= "core = 7.x\n"; 253 254 if (is_array($module_data['module_files'])) { 255 foreach ($module_data['module_files'] as $file) { 256 $info .= 'files[] = '. $file ."\n"; 257 } 258 } 259 260 return $info; 261 } 262 } 263 264 265 /** 266 * Generate module code. 267 * 268 * @param $module_data 269 * An associative array of data for the module, passed by reference so data 270 * on generated files can be added. 271 * The keys can *mostly* be taken straight from form values. They are as follows: 272 * - 'module_root_name' 273 * - 'module_readable_name' 274 * - 'module_short_description' 275 * - 'module_help_text' 276 * - 'hooks': An associative array whose keys are full hook names 277 * (eg 'hook_menu'), where requested hooks have a value of TRUE. 278 * Unwanted hooks may also be included as keys provided their value is FALSE. 279 * - 'module_dependencies': a string of dependencies, eg 'forum views'. 280 * - 'module_package': the module package. 281 * - 'module_files': added by this function. A flat array of filenames that have been generated. 282 * @param $bare 283 * If true, omit header and footers and output only hook code. 284 * @return 285 * An array of code, indexed by filename. Eg, 286 * 'modulename.module' => CODE 287 */ 288 function module_builder_generate_module(&$module_data, $bare = FALSE) { 289 // Get a set of hook declarations and function body templates for the hooks we want. 290 // $hook_data is of the form: 291 // 'hook_foo' => array( 'declaration' => DATA, 'template' => DATA ) 292 $hook_file_data = module_builder_get_templates($module_data); 293 if (is_null($hook_file_data)) { 294 return NULL; 295 } 296 297 // There must always be a MODULE.module file, even if there are no hooks to 298 // go in it. 299 // (Slight niggle: it gets put at the end :/) 300 $hook_file_data += array( 301 $module_data['module_root_name'] . '.module' => array(), 302 ); 303 304 //print_r($module_data); 305 //dsm($hook_file_data); 306 307 // Iterate over our data array, because it's in a pretty order. 308 // by each needed file of code. 309 $module_code = array(); 310 foreach ($hook_file_data as $filename => $hook_data) { 311 $class = module_builder_get_class('code'); 312 $generator = new $class($module_data); 313 $generator->hook_data = $hook_data; 314 $generator->filename = $filename; 315 316 if ($bare) { 317 $code = $generator->code_body; 318 } 319 else { 320 $code = $generator->build(); 321 } 322 323 //dsm($code); 324 //print $code; 325 326 $module_code[$filename] = $code; 327 // Add the generated filename to the module data for the info generation to find. 328 $module_data['module_files'][] = $filename; 329 } // foreach file 330 331 //print_r($module_data); 332 333 return $module_code; 334 } 335 336 /** 337 * Get the doxygen header for a given hook. 338 * This does not return with an initial newline so the doc block may be inserted into existing code. 339 * 340 * @param 341 * The long hook name, eg 'hook_menu'. 342 */ 343 function module_builder_code_hook_doxy($hook_name) { 344 return <<<EOT 345 /** 346 * Implementation of $hook_name(). 347 */ 348 349 EOT; 350 } 351 352 /** 353 * Helper function for module_builder_generate_module 354 * 355 * Returns an array of hook data and templates for the requested hooks. 356 * This is handled live rather than in process.inc to allow the user to alter 357 * their custom hook templates. 358 * 359 * @return 360 * An array of the form: 361 * 'destination file' => array( 362 * 'hook_foo' => array( 'declaration' => DATA, 'template' => DATA ) 363 */ 364 function module_builder_get_templates($module_data) { 365 // begin assembling data 366 // build an array $hook_data of all the stuff we know about hooks 367 // of the form: 368 // 'hook_foo' => array( 'declaration' => DATA, 'template' => DATA ) 369 $hook_data = array(); 370 371 // Check for custom functions file, else use default 372 $path = module_builder_get_path('templates'); 373 374 if (file_exists("$path/hooks-custom.template")) { 375 $template_file = file_get_contents("$path/hooks-custom.template"); 376 } 377 else { 378 $template_file = file_get_contents("$path/hooks.template"); 379 } 380 381 // Get array of our hook function body templates from our own / custom template files. 382 // This is not necessarily all hooks that exist -- not all have template entries. 383 // This array is in the same order as they occur in the files and already in the format wanted. 384 // Include generating component file. 385 module_builder_include('process'); 386 $template_data = module_builder_parse_template($template_file); 387 388 // print_r($hook_data); ok! 389 390 // Check for node hooks; these will overwrite core hooks if found. 391 if (isset($module_data['hooks']['hook_node_info'])) { 392 if (file_exists("$path/node_hooks-custom.template")) { 393 $template_file = file_get_contents("$path/node_hooks-custom.template"); 394 } 395 else { 396 $template_file = file_get_contents("$path/node_hooks.template"); 397 } 398 $custom_hooks = module_builder_parse_template($template_file); 399 foreach ($custom_hooks as $hook_name => $hook_template) { 400 // add or clobber our existing templates 401 $template_data[$hook_name] = $hook_template; 402 } 403 } 404 405 // $template_data is now an array of the form: 406 // [hook name] => array('template' => DATA) 407 // in a pretty order which we want to hold on to. 408 409 //print_r($template_data); 410 //dsm($template_data); 411 412 // Get array of the hook function declarations from the downloaded hook data. 413 // This is a complete list of all hooks that exist. 414 // In the form: 'hook_foo' => array('declaration', 'destination') 415 // This array is the order they are in the files from d.org: alphabetical apparently. 416 // We don't care for this order! 417 $hook_function_declarations = module_builder_get_hook_declarations(); 418 // If we get NULL then no hook data exists: return NULL again. 419 if (is_null($hook_function_declarations)) { 420 return NULL; 421 } 422 423 //print_r($hook_function_declarations); 424 425 // Remove all hooks we don't care about. 426 // First filter out the keys with 0 values that come from UI form. 427 $requested_hooks = array_filter($module_data['hooks']); 428 $hook_function_declarations = array_intersect_key($hook_function_declarations, $requested_hooks); 429 $template_data = array_intersect_key($template_data, $requested_hooks); 430 431 //print_r($requested_hooks); 432 433 // Start hierarchical building hook data. 434 // Make the destination filenames, and add an item for each destination file. 435 foreach ($hook_function_declarations as $hook_name => $hook) { 436 $destination = str_replace('%module', $module_data['module_root_name'], $hook['destination']); 437 $hook_function_declarations[$hook_name]['destination'] = $destination; 438 $hook_data[$destination] = array(); 439 } 440 441 // Now iterate over the template data so we use its order 442 // and grab data from the declarations array 443 // and put it all into the final data array 444 foreach (array_keys($template_data) as $hook_name) { 445 $destination = $hook_function_declarations[$hook_name]['destination']; 446 $hook_data[$destination][$hook_name]['declaration'] = $hook_function_declarations[$hook_name]['declaration']; 447 $hook_data[$destination][$hook_name]['template'] = $template_data[$hook_name]['template']; 448 } 449 450 //dsm($hook_data); 451 452 // Not all hooks have template data 453 foreach ($hook_function_declarations as $hook_name => $hook) { 454 $destination = $hook['destination']; 455 if (!isset($hook_data[$destination][$hook_name]['declaration'])) { 456 $hook_data[$destination][$hook_name]['declaration'] = $hook_function_declarations[$hook_name]['declaration']; 457 } 458 } 459 460 461 //dsm($hook_data); 462 463 // $hook_data is now a complete representation of all we know about the requested hooks 464 return $hook_data; 465 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Jul 9 18:01:44 2012 | Cross-referenced by PHPXref 0.7 |