| 
<?php
 namespace JLaso\SlimRoutingManager;
 
 use \Slim\Slim;
 
 class RoutingCacheManager
 {
 
 protected $cacheDir;
 protected $rootDir;
 
 /**
 * @param array $options
 */
 function __construct($options = array())
 {
 $tmp = preg_split('|/vendor/|', __DIR__);
 $this->rootDir = $tmp[0] . "/";
 if(!isset($options['cache'])){
 $options['cache'] = $tmp[0] . '/cache/routing';
 }
 @mkdir($options['cache'], 0777, true);
 $this->cacheDir = $options['cache'];
 if(isset($options['controller'])){
 if(is_array($options['controller'])){
 $controllers = $options['controller'];
 }else{
 $controllers = array($options['controller']);
 }
 }else{
 $controllers = array($tmp[0] . '/app/controller');
 }
 if(count($controllers)){
 foreach($controllers as $controllerPath){
 $this->loadPath(realpath($controllerPath));
 }
 }
 }
 
 
 /*******************
 *                 *
 * CACHE FUNCTIONS *
 *                 *
 *******************/
 
 /**
 * gets the full path and the name of cache file
 *
 * @param $class
 *
 * @return string
 */
 protected function cacheFile($class)
 {
 return $this->cacheDir . '/' . $class . '.php';
 }
 
 /**
 * This method writes the cache content into cache file
 *
 * @param $class
 * @param $content
 *
 * @return string
 */
 protected function writeCache($class, $content)
 {
 $date = date("Y-m-d h:i:s");
 $content = <<<EOD
 <?php
 
 
 /**
 * Generated with RoutingCacheManager
 *
 * on {$date}
 */
 
 \$app = Slim\Slim::getInstance();
 
 {$content}
 
 EOD;
 $fileName = $this->cacheFile($class);
 file_put_contents($fileName, $content);
 
 return $fileName;
 }
 
 /**
 * Generates new file and return cachefile name
 * @param $classFile
 *
 * @return string
 */
 protected function updateAndGetCacheFileName($classFile)
 {
 $className = $this->className($classFile);
 
 if($this->hasChanged($classFile)){
 $content = $this->processClass($classFile);
 $this->writeCache($className, $content);
 $this->setDateFromClassFile($classFile);
 }
 
 return $this->cacheFile($className);
 }
 
 /**
 * Return cachefile contents
 *
 * @param $classFile
 *
 * @return string
 */
 protected function getCache($classFile)
 {
 return file_get_contents($this->updateAndGetCacheFileName($classFile));
 }
 
 /**
 * Process the cachefile, in PHP require is enough
 *
 * @param $classFile
 *
 * @throws \Exception
 */
 protected function processCache($classFile)
 {
 require_once($this->updateAndGetCacheFileName($classFile));
 }
 
 /**
 * Indicates if the classfile has a diferent modify time that cache file
 *
 * @param $classFile
 *
 * @return bool
 */
 protected function hasChanged($classFile)
 {
 $className = $this->className($classFile);
 $cacheFile = $this->cacheFile($className);
 $cacheDate = file_exists($cacheFile) ? filemtime($cacheFile) : 0;
 $fileDate  = filemtime($classFile);
 
 return ($fileDate != $cacheDate);
 }
 
 
 /*******************
 *                 *
 * CLASS FUNCTIONS *
 *                 *
 *******************/
 
 /**
 * Sets the modify time of cache file according to classfile
 *
 * @param $classFile
 */
 protected function setDateFromClassFile($classFile)
 {
 $className = $this->className($classFile);
 $cacheFile = $this->cacheFile($className);
 $fileDate  = filemtime($classFile);
 touch($cacheFile, $fileDate);
 }
 
 /**
 * Extracts the className through the classfile name
 *
 * @param $classFile
 *
 * @return mixed
 * @throws \Exception
 */
 protected function className($classFile)
 {
 $classFile = str_replace($this->rootDir, "", $classFile);
 $className = str_replace(array(".php", "/"), array("", "_"), $classFile);
 
 return $className;
 }
 
 /**
 * @param $classFile
 *
 * @return string
 * @throws \Exception
 */
 protected function processClass($classFile)
 {
 $className = '';
 $content   = file_get_contents($classFile);
 $result    = '';
 
 preg_match_all('/class\s+(\w*)\s*(extends\s+)?([^{])*/s', $content, $mclass, PREG_SET_ORDER);
 $className = $mclass[0][1];
 if (!$className){
 throw new \Exception(sprintf('class not found in %s', $classFile));
 }
 
 preg_match_all('|(/\*\*[^{]*?{)|', $content, $match, PREG_PATTERN_ORDER);
 
 foreach ($match[0] as $k => $m) {
 $function = '?';
 $comments = '';
 if (!substr_count($m, 'class')) {
 $function = substr_count($m, 'function') ? 'yes' : 'no';
 if ($function == 'yes') {
 preg_match_all('/(\/\*\*.*\*\/)/s', $m, $mc, PREG_PATTERN_ORDER);
 $comments = nl2br($mc[0][0]);
 preg_match_all('/\*\/\s+(public\s+)?(static\s+)?function\s+([^\(]*)\(/s', $m, $mf, PREG_SET_ORDER);
 $functionName = $mf[0][3];
 preg_match_all("/\*\s+@Route\s*\('([^']*)'\)/s", $comments, $params, PREG_SET_ORDER);
 $route = $params[0][1];
 preg_match_all("/\*\s+@Method\s*\('([^']*)'\)/s", $comments, $params, PREG_SET_ORDER);
 $method = isset($params[0][1]) ? strtoupper($params[0][1]) : 'GET';
 preg_match_all("/\*\s+@Name\s*\('([^']*)'\)/s", $comments, $params, PREG_SET_ORDER);
 $name = strtolower($params[0][1]);
 $result .= sprintf(
 '$app->map("%s", "%s::___%s")->via("%s")->name("%s");' . PHP_EOL,
 $route, $className, $functionName, str_replace(',','","',$method), $name
 );
 }
 }
 }
 
 return $result;
 }
 
 /******************
 *                *
 * PATH FUNCTIONS *
 *                *
 ******************/
 
 /**
 * Main method to invoke the routing system
 *
 * @param $phpFile
 */
 protected function loadRoute($phpFile)
 {
 require_once $phpFile;
 $this->processCache($phpFile);
 }
 
 /**
 * Reads the contents of this dir and returns only dirs
 * that have first letter capitalized
 *
 * @return array
 */
 protected static function readdir($dir)
 {
 $entries = array();
 foreach (scandir($dir) as $entry) {
 if(($entry != '.') && ($entry != '..')){
 $current = "$dir/$entry";
 if($current != $dir){
 if(is_dir($current)){
 $aux = self::readdir($current);
 $entries = array_merge($entries, $aux);
 }else{
 if(preg_match("/\w*?Controller.php/", $entry)){
 $entries[] = $current;
 }
 }
 }
 }
 }
 
 return $entries;
 }
 
 /**
 * Load all Controller classes in an entire path
 *
 * @param $path
 */
 protected function loadPath($path)
 {
 $controllers = self::readdir($path);
 if(count($controllers)){
 foreach($controllers as $controller){
 $this->loadRoute($controller);
 }
 }
 }
 
 
 }
 
 |