[ Index ]

PHP Cross Reference of Akelos Framework

title

Body

[close]

/ -> AkClassExtender.php (source)

   1  <?php
   2  
   3  
   4  defined('AK_CLASS_EXTENDER_ENABLE_CACHE') ? null : define('AK_CLASS_EXTENDER_ENABLE_CACHE', !AK_DEV_MODE);
   5  /**
   6   * @ WARNING too experimental. This is a proof of concept. Do not use it for production.
   7   * 
   8   * The AkClassExtender provides the means for extending core Akelos Framework
   9   * functionality by chaining multiple objects and creating an extended 
  10   * composite class of the original.
  11   * 
  12   * It is a good practice maintaining the level of parents low when writing OO
  13   * code, but PHP classes are closed and do not allow runtime modification so
  14   * this method will allow others to write core extensions that modify the default
  15   * Akelos Framework behavior.
  16   * 
  17   * This technique requires that the participants of the class chain are not included yet
  18   * during execution, ass participants code will be joined, modified and cached for
  19   * including it as a single source file.
  20   */
  21  class AkClassExtender
  22  {
  23      var $_extended_classes;
  24  
  25      function extendClassWithSource($class_name_to_extend, $extension_path, $priority = 10)
  26      {
  27          $this->_extended_classes[$class_name_to_extend][$priority][] = $extension_path;
  28      }
  29  
  30      function _getExtensionFilePaths($class_name_to_extend)
  31      {
  32          $extension_files = array();
  33          if(!empty($this->_extended_classes[$class_name_to_extend])){
  34              $extensions = $this->_extended_classes[$class_name_to_extend];
  35              ksort($extensions);
  36              foreach ($extensions as $files){
  37                  $extension_files = array_merge($extension_files, $files);
  38              }
  39          }
  40          return $extension_files;
  41      }
  42  
  43      function _getExtensionSourceAndChecksum($class_name_to_extend)
  44      {
  45          $file_contents = '';
  46          $file_paths = $this->_getExtensionFilePaths($class_name_to_extend);
  47          $checksum = md5(serialize($file_paths));
  48          if(!$this->_canIncludeMergedFile($class_name_to_extend, $checksum)){
  49              foreach ($file_paths as $file_path){
  50                  if(is_file($file_path)){
  51                      $file_contents .= Ak::file_get_contents($file_path);
  52                  }
  53              }
  54              return array($checksum, $file_contents);
  55          }else{
  56              return false;
  57          }
  58      }
  59  
  60      function extendClasses()
  61      {
  62          foreach (array_keys($this->_extended_classes) as $class_name_to_extend){
  63              $this->makeClassExtensible($class_name_to_extend);
  64          }
  65      }
  66  
  67      function makeClassExtensible($class_name_to_extend)
  68      {
  69          list($checksum, $source) = $this->_getExtensionSourceAndChecksum($class_name_to_extend);
  70          $merge_path = AK_TMP_DIR.DS.'.lib';
  71          if($source){
  72              if(preg_match_all('/[ \n\t]*([a-z]+)[ \n\t]*extends[ \n\t]*('.$class_name_to_extend.')[ \n\t]*[ \n\t]*{/i', $source, $matches)){
  73                  $replacements = array();
  74                  $extended_by = array();
  75  
  76                  foreach ($matches[2] as $k => $class_to_extend){
  77                      if(empty($last_method) && class_exists($class_to_extend)){
  78                          $last_method = $class_to_extend;
  79                      }
  80                      if($class_to_extend == $last_method || !empty($extended_by[$class_to_extend]) && in_array($last_method,$extended_by[$class_to_extend])){
  81                          if(!class_exists($matches[1][$k])){
  82                              $replacements[trim($matches[0][$k],"\n\t {")] = $matches[1][$k].' extends '.$last_method;
  83                              $last_method = $matches[1][$k];
  84                              $extended_by[$class_to_extend][] = $last_method;
  85                          } else {
  86                              trigger_error(Ak::t('The class %class is already defined and can\'t be used for extending %parent_class', array('%class' => $matches[1][$k], '%parent_class' => $class_name_to_extend)), E_NOTICE);
  87                          }
  88                      }
  89                  }
  90                  $source = str_replace(array_keys($replacements), array_values($replacements), $source);
  91              }
  92              $source = "$source<?php class Extensible$class_name_to_extend extends $last_method{} ?>";
  93              if(md5($source) != @md5_file($merge_path.DS.'Extensible'.$class_name_to_extend.'.php')){
  94                  Ak::file_put_contents($merge_path.DS.'Extensible'.$class_name_to_extend.'.php', $source);
  95                  Ak::file_put_contents($merge_path.DS.'checksums'.DS.'Extensible'.$class_name_to_extend, $checksum);
  96              }
  97          }
  98  
  99          include_once($merge_path.DS.'Extensible'.$class_name_to_extend.'.php');
 100      }
 101  
 102      function _canIncludeMergedFile($class_name_to_extend, $checksum)
 103      {
 104          $merge_path = AK_TMP_DIR.DS.'.lib';
 105          if(AK_CLASS_EXTENDER_ENABLE_CACHE && file_exists($merge_path.DS.'Extensible'.$class_name_to_extend.'.php') &&
 106          Ak::file_get_contents($merge_path.DS.'checksums'.DS.'Extensible'.$class_name_to_extend) == $checksum){
 107              return true;
 108          }
 109          return false;
 110      }
 111  }
 112  
 113  
 114  ?>


Generated: Mon Oct 27 12:43:49 2008 Cross-referenced by PHPXref 0.6