diff --git a/src/Filesystem/ClassFinder.php b/src/Filesystem/ClassFinder.php new file mode 100644 index 0000000..7699ee5 --- /dev/null +++ b/src/Filesystem/ClassFinder.php @@ -0,0 +1,126 @@ +in($directory)->name('*.php') as $file) { + $classes[] = $this->findClass($file->getRealPath()); + } + return array_filter($classes); + } + /** + * Extract the class name from the file at the given path. + * + * @param string $path + * @return string|null + */ + public function findClass($path) + { + $namespace = null; + $tokens = token_get_all(file_get_contents($path)); + foreach ($tokens as $key => $token) { + if ($this->tokenIsNamespace($token)) { + $namespace = $this->getNamespace($key + 2, $tokens); + } elseif ($this->tokenIsClassOrInterface($token)) { + return ltrim($namespace.'\\'.$this->getClass($key + 2, $tokens), '\\'); + } + } + } + /** + * Find the namespace in the tokens starting at a given key. + * + * @param int $key + * @param array $tokens + * @return string|null + */ + protected function getNamespace($key, array $tokens) + { + $namespace = null; + $tokenCount = count($tokens); + for ($i = $key; $i < $tokenCount; $i++) { + if ($this->isPartOfNamespace($tokens[$i])) { + $namespace .= $tokens[$i][1]; + } elseif ($tokens[$i] == ';') { + return $namespace; + } + } + } + /** + * Find the class in the tokens starting at a given key. + * + * @param int $key + * @param array $tokens + * @return string|null + */ + protected function getClass($key, array $tokens) + { + $class = null; + $tokenCount = count($tokens); + for ($i = $key; $i < $tokenCount; $i++) { + if ($this->isPartOfClass($tokens[$i])) { + $class .= $tokens[$i][1]; + } elseif ($this->isWhitespace($tokens[$i])) { + return $class; + } + } + } + /** + * Determine if the given token is a namespace keyword. + * + * @param array|string $token + * @return bool + */ + protected function tokenIsNamespace($token) + { + return is_array($token) && $token[0] == T_NAMESPACE; + } + /** + * Determine if the given token is a class or interface keyword. + * + * @param array|string $token + * @return bool + */ + protected function tokenIsClassOrInterface($token) + { + return is_array($token) && ($token[0] == T_CLASS || $token[0] == T_INTERFACE); + } + /** + * Determine if the given token is part of the namespace. + * + * @param array|string $token + * @return bool + */ + protected function isPartOfNamespace($token) + { + return is_array($token) && ($token[0] == T_STRING || $token[0] == T_NS_SEPARATOR); + } + /** + * Determine if the given token is part of the class. + * + * @param array|string $token + * @return bool + */ + protected function isPartOfClass($token) + { + return is_array($token) && $token[0] == T_STRING; + } + /** + * Determine if the given token is whitespace. + * + * @param array|string $token + * @return bool + */ + protected function isWhitespace($token) + { + return is_array($token) && $token[0] == T_WHITESPACE; + } +} diff --git a/src/Metadata/ClassFinder.php b/src/Metadata/ClassFinder.php index 7521a4c..0d37226 100644 --- a/src/Metadata/ClassFinder.php +++ b/src/Metadata/ClassFinder.php @@ -3,7 +3,7 @@ namespace ProAI\Annotations\Metadata; use Illuminate\Console\AppNamespaceDetectorTrait; -use Illuminate\Filesystem\ClassFinder as FilesystemClassFinder; +use ProAI\Annotations\Filesystem\ClassFinder as FilesystemClassFinder; class ClassFinder { diff --git a/src/Metadata/RouteScanner.php b/src/Metadata/RouteScanner.php index fbc042f..e389863 100644 --- a/src/Metadata/RouteScanner.php +++ b/src/Metadata/RouteScanner.php @@ -76,17 +76,16 @@ public function parseController($class) $classAnnotations = $this->reader->getClassAnnotations($reflectionClass); $controllerMetadata = []; - $middleware = []; // find entity parameters and plugins foreach ($classAnnotations as $annotation) { // controller attributes if ($annotation instanceof \ProAI\Annotations\Annotations\Controller) { $prefix = $annotation->prefix; - $middleware = $this->addMiddleware($middleware, $annotation->middleware); + $middleware = $annotation->middleware; } if ($annotation instanceof \ProAI\Annotations\Annotations\Middleware) { - $middleware = $this->addMiddleware($middleware, $annotation->value); + $middleware = $annotation->value; } // resource controller @@ -107,10 +106,13 @@ public function parseController($class) // find routes foreach ($reflectionClass->getMethods() as $reflectionMethod) { + $name = $reflectionMethod->getName(); $methodAnnotations = $this->reader->getMethodAnnotations($reflectionMethod); + $routeMetadata = []; + // controller method is resource route if (! empty($resource) && in_array($name, $resource['methods'])) { $routeMetadata = [ @@ -124,8 +126,10 @@ public function parseController($class) } // controller method is route - if ($route = $this->hasHttpMethodAnnotation($name, $methodAnnotations)) { - $routeMetadata = [ + if ($routes = $this->hasHttpMethodAnnotation($name, $methodAnnotations)) { + $routeMetadata = []; + foreach($routes as $route){ + $routeMetadata[] = [ 'uri' => $route['uri'], 'controller' => $class, 'controllerMethod' => $name, @@ -133,27 +137,44 @@ public function parseController($class) 'as' => $route['as'], 'middleware' => $route['middleware'] ]; + } } // add more route options to route metadata - if (! empty($routeMetadata)) { - if (! empty($middleware)) { - $routeMetadata['middleware'] = $middleware; + if (! empty($routeMetadata)) { + if(!isset($routeMetadata[0])){ + $temp = []; + $temp[] = $routeMetadata; + $routeMetadatas = $temp; + } else { + $routeMetadatas = $routeMetadata; } + $idx = 0; + foreach($routeMetadatas as $routeMetadata){ + $idx++; // add other method annotations foreach ($methodAnnotations as $annotation) { - if ($annotation instanceof \ProAI\Annotations\Annotations\Middleware) { - $middleware = $this->addMiddleware($middleware, $routeMetadata['middleware']); - } + if ($annotation instanceof \ProAI\Annotations\Annotations\Middleware) { + if (!empty($middleware) && isset($routeMetadata['middleware'])) { + $routeMetadata['middleware'] = [$middleware, $annotation->value]; + continue; + } + + $routeMetadata['middleware'] = $annotation->value; + } } - // add global prefix and middleware - if (! empty($prefix)) { + // add global prefix and middleware + if (! empty($prefix)) { $routeMetadata['uri'] = $prefix.'/'.$routeMetadata['uri']; - } + } + if (! empty($middleware) && empty($routeMetadata['middleware'])) { + $routeMetadata['middleware'] = $middleware; + } - $controllerMetadata[$name] = $routeMetadata; + $controllerMetadata[$name.$idx] = $routeMetadata; + } } } @@ -211,74 +232,69 @@ protected function getResourcePath($method) */ protected function hasHttpMethodAnnotation($name, $methodAnnotations) { + + $parseAnnotation = function ($httpMethod,$annotation){ + // options + $as = (! empty($annotation->as)) ? $annotation->as : ''; + $middleware = (! empty($annotation->middleware)) ? $annotation->middleware : ''; + + $uri = (empty($annotation->value)) ? str_replace("_", "-", snake_case($name)) : $annotation->value; + return [ + 'uri' => $uri, + 'httpMethod' => $httpMethod, + 'as' => $as, + 'middleware' => $middleware + ]; + + }; + + + $return = []; + foreach ($methodAnnotations as $annotation) { // check for http method annotation if ($annotation instanceof \ProAI\Annotations\Annotations\Get) { $httpMethod = 'GET'; - break; + $return[] = $parseAnnotation($httpMethod,$annotation); + // break; } if ($annotation instanceof \ProAI\Annotations\Annotations\Post) { $httpMethod = 'POST'; - break; + $return[] = $parseAnnotation($httpMethod,$annotation); + //break; } if ($annotation instanceof \ProAI\Annotations\Annotations\Options) { $httpMethod = 'OPTIONS'; - break; + $return[] = $parseAnnotation($httpMethod,$annotation); + // break; } if ($annotation instanceof \ProAI\Annotations\Annotations\Put) { $httpMethod = 'PUT'; - break; + $return[] = $parseAnnotation($httpMethod,$annotation); + //break; } if ($annotation instanceof \ProAI\Annotations\Annotations\Patch) { $httpMethod = 'PATCH'; - break; + $return[] = $parseAnnotation($httpMethod,$annotation); + // break; } if ($annotation instanceof \ProAI\Annotations\Annotations\Delete) { $httpMethod = 'DELETE'; - break; + $return[] = $parseAnnotation($httpMethod,$annotation); + //break; } if ($annotation instanceof \ProAI\Annotations\Annotations\Any) { $httpMethod = 'ANY'; - break; + $return[] = $parseAnnotation($httpMethod,$annotation); + //break; } } - // http method found - if (! empty($httpMethod)) { - // options - $as = (! empty($annotation->as)) ? $annotation->as : ''; - - $uri = (empty($annotation->value)) ? str_replace("_", "-", snake_case($name)) : $annotation->value; - - return [ - 'uri' => $uri, - 'httpMethod' => $httpMethod, - 'as' => $as, - 'middleware' => $this->addMiddleware([], $annotation->middleware) - ]; - } - - return null; - } - - /** - * Add middleware - * - * @param array $middleware - * @param array $newMiddleware - * @return array - */ - protected function addMiddleware($middleware, $newMiddleware) - { - if (! empty($newMiddleware)) { - $newMiddleware = (is_array($newMiddleware)) - ? $newMiddleware - : [$newMiddleware]; - - return array_merge($middleware, $newMiddleware); + if(count($return) > 0){ + return $return; + } else { + return false; } - - return $middleware; } } diff --git a/src/Providers/MetadataServiceProvider.php b/src/Providers/MetadataServiceProvider.php index 36fefeb..173bc88 100644 --- a/src/Providers/MetadataServiceProvider.php +++ b/src/Providers/MetadataServiceProvider.php @@ -4,7 +4,7 @@ use Illuminate\Support\ServiceProvider; use ProAI\Annotations\Metadata\ClassFinder; -use Illuminate\Filesystem\ClassFinder as FilesystemClassFinder; +use ProAI\Annotations\Filesystem\ClassFinder as FilesystemClassFinder; use ProAI\Annotations\Metadata\AnnotationLoader; use Doctrine\Common\Annotations\AnnotationReader; diff --git a/src/Routing/Generator.php b/src/Routing/Generator.php index d0eeb3c..12b4773 100644 --- a/src/Routing/Generator.php +++ b/src/Routing/Generator.php @@ -100,11 +100,10 @@ public function generateRoutes($metadata) // middleware option if (! empty($routeMetadata['middleware'])) { - $middleware = implode("', '",$routeMetadata['middleware']); - if (count($routeMetadata['middleware']) > 1) { - $middleware = "['".$middleware."']"; + if (is_array($routeMetadata['middleware'])) { + $middleware = "['".implode("', '",$routeMetadata['middleware'])."']"; } else { - $middleware = "'".$middleware."'"; + $middleware = "'".$routeMetadata['middleware']."'"; } $options[] = "'middleware' => ".$middleware; }