Created
October 2, 2012 11:05
-
-
Save musaid/3818209 to your computer and use it in GitHub Desktop.
Handler Loader Class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* class to load the handlers as callbacks for the given events/tags | |
* @author musaid <musaid@alliedmaldives.net> | |
* @version v0.1 | |
* | |
* usage: | |
* $handle = new HandlerLoader(); | |
* var_dump($handle->getHandlers('/var/www/crawler/folder/')); | |
* var_dump($handle->getHandlers('/var/www/crawler/folder/', array('handler', 'denormalizer'))); | |
*/ | |
class HandlerLoader { | |
/** | |
* get handlers from the files in the given path | |
* @param string $path directory/path name | |
* @param array $tags tags to distinguish relevant files | |
* @return array $handlers relevant handlers | |
*/ | |
public function getHandlers($path, $tags = array()) { | |
$files = $this->getFiles($path); | |
$closures = array(); | |
$methods = array(); | |
$handlers = array(); | |
foreach ($files as $file) { | |
$tokens = $this->tokenize($file); | |
$handlers = $this->getClosures($handlers, $file, $tokens, $tags); | |
$handlers = $this->getMethods($handlers, $tokens, $tags); | |
} | |
return $handlers; | |
} | |
/** | |
* get the files in the given path | |
* @param string $path directory/path name | |
* @param string $ext extension of the files needed | |
* @return array $files list of files in the directory/path | |
*/ | |
protected function getFiles($path, $ext = '.php') { | |
// handle the extension if a . is provided | |
if (preg_match('/^\.\w+/', $ext)) | |
$ext = str_replace('.', '', $ext); | |
$iterator = new FilesystemIterator($path); | |
while($iterator->valid()) { | |
if (preg_match('/'.$ext.'/i', $iterator->getExtension())) { | |
$file_name = $iterator->getPathname(); | |
$files[] = $file_name; | |
} | |
$iterator->next(); | |
} | |
return $files; | |
} | |
/** | |
* tokenize the files into an array | |
* @param string $file file name including the path | |
* @return array files content as tokens | |
*/ | |
protected function tokenize($file) { | |
return token_get_all(file_get_contents($file)); | |
} | |
/** | |
* count the matching tags present in the docblock of the method/closure | |
* @param string $str docblock comment as a string | |
* @param array $tag_array tags to be compared | |
* @return int $matched_tag_count number of matched tags | |
*/ | |
protected function tagCount($str, $tag_array = array()) { | |
preg_match('/@tags ([a-zA-Z0-9_\x7f-\xff, \n*\t]*)/ms', $str, $tags); | |
$tags = explode(',', isset($tags[1]) ? $tags[1] : null); | |
$tags = array_map(function($item) { return trim($item, "* \t\r\n"); }, $tags); | |
$matched_tag_count = 0; | |
foreach ($tag_array as $tag_name) { | |
foreach ($tags as $tags_name) { | |
if ($tag_name == $tags_name) { | |
$matched_tag_count++; | |
} | |
} | |
} | |
return $matched_tag_count; | |
} | |
/** | |
* get the events related to each method/closure | |
* @param string $str docblock comment as a string | |
* @return string event associated with the method/closure | |
*/ | |
protected function getEvent($str) { | |
preg_match('/@event ([a-zA-Z0-9_\x7f-\xff, \t\x5C]*)/ms', $str, $event); | |
return !empty($event) ? $event[1] : null; | |
} | |
/** | |
* get the closures with the given tags and it's associated event | |
* throws an array if the closure misses the event annotation | |
* @param array $handlers previous handlers (if any) | |
* @param string $file file name where the relevant handlers belong to | |
* @param array $tokens tokens to search for handlers | |
* @param array $tags tags associated to the handlers (if any) | |
* @return array matched handlers as callbacks | |
*/ | |
protected function getClosures($handlers = array(), $file, $tokens, $tags) { | |
// require the file | |
require_once($file); | |
foreach ($tokens as $token) { | |
if (!is_array($token) || $token[0] != T_VARIABLE) continue; | |
$var_name = str_replace('$', '', $token[1]); | |
if (!is_callable($$var_name)) continue; | |
$rf_func = new ReflectionFunction($$var_name); | |
$event = $this->getEvent($rf_func->getDocComment()); | |
if (empty($event)) { | |
throw new Exception("No Event Provided in handler $$var_name in {$file} on line ".$rf_func->getStartLine(), 1); | |
} | |
if (!empty($tags) && $this->tagCount($rf_func->getDocComment(), $tags) == 0) continue; | |
if (!isset($handlers[$event])) { | |
$handlers[$event] = array(); | |
} | |
$handlers[$event][] = $$var_name; | |
} | |
return $handlers; | |
} | |
/** | |
* get the methods with the given tags and it's associated event | |
* throws an array if the closure misses the event annotation | |
* @param array $handlers previous handlers (if any) | |
* @param array $tokens tokens to search for handlers | |
* @param array $tags tags associated to the handlers (if any) | |
* @return array matched handlers as a callback (class name and method name) | |
*/ | |
protected function getMethods($handlers = array(), $tokens, $tags) { | |
$callback = false; | |
$class_token = false; | |
$i=0; | |
foreach ($tokens as $token) { | |
if (!is_array($token)) continue; | |
if ($token[0] == T_CLASS) { | |
$class_token = true; | |
} else if ($class_token && $token[0] == T_STRING) { | |
$reflection = new ReflectionClass($token[1]); | |
foreach($reflection->getMethods(ReflectionMethod::IS_PUBLIC) as $prop) { | |
$method = $prop->getName(); | |
$rf_method = new ReflectionMethod($token[1], $method); | |
$callback = array($token[1], $method); | |
if (!is_callable($callback)) continue; | |
$event = $this->getEvent($rf_method->getDocComment()); | |
if (empty($event)) { | |
throw new Exception("No Event Provided in handler '$method' in ".$rf_method->getFileName()." on line ".$rf_method->getStartLine(), 1); | |
} | |
if (!empty($tags) && $this->tagCount($rf_method->getDocComment(), $tags) == 0) continue; | |
if (!isset($handlers[$event])) { | |
$handlers[$event] = array(); | |
} | |
$handlers[$event][] = $callback; | |
} | |
$class_token = false; | |
} | |
$i++; | |
} | |
return $handlers; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment