[ Index ]

PHP Cross Reference of Drupal 6 (yi-drupal)

title

Body

[close]

/sites/all/modules/module_builder/includes/ -> generate.inc (source)

   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  }


Generated: Mon Jul 9 18:01:44 2012 Cross-referenced by PHPXref 0.7