Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow multiple route annontations per function #4

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions src/Console/EventClearCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,9 @@ public function fire()

$this->info('Events cleared successfully!');
}

public function handle()
{
$this->fire();
}
}
5 changes: 5 additions & 0 deletions src/Console/EventScanCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,9 @@ public function fire()

$this->info('Events registered successfully!');
}

public function handle()
{
$this->fire();
}
}
6 changes: 6 additions & 0 deletions src/Console/RouteClearCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,10 @@ public function fire()

$this->info('Routes cleared successfully!');
}

public function handle()
{
$this->fire();
}

}
6 changes: 6 additions & 0 deletions src/Console/RouteScanCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,10 @@ public function fire()

$this->info('Routes registered successfully!');
}

public function handle()
{
$this->fire();
}

}
126 changes: 126 additions & 0 deletions src/Filesystem/ClassFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php
namespace ProAI\Annotations\Filesystem;
use Symfony\Component\Finder\Finder;
class ClassFinder
{
/**
* Find all the class and interface names in a given directory.
*
* @param string $directory
* @return array
*/
public function findClasses($directory)
{
$classes = [];
foreach (Finder::create()->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;
}
}
2 changes: 1 addition & 1 deletion src/Metadata/ClassFinder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
130 changes: 73 additions & 57 deletions src/Metadata/RouteScanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 = [
Expand All @@ -124,36 +126,55 @@ 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,
'httpMethod' => $route['httpMethod'],
'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;
}
}
}

Expand Down Expand Up @@ -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;
}
}
Loading