Compare commits
28
Commits
61b84bfd09
..
v2.1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13ccb13a0b | ||
|
|
67aa7e513d | ||
|
|
eac8269c48 | ||
|
|
fa0430a3fc | ||
|
|
237f0a30d2 | ||
|
|
b093f53a6b | ||
|
|
dd239c63bc | ||
|
|
0db34fe228 | ||
|
|
fa4fe32277 | ||
|
|
e20157a162 | ||
|
|
63c7dc23f9 | ||
|
|
a4d99dfe08 | ||
|
|
f199cc7085 | ||
|
|
08c0ffacab | ||
|
|
6ba66dcd37 | ||
|
|
81fa3d49c7 | ||
|
|
fcb332ae53 | ||
|
|
133672b347 | ||
|
|
34a3351ed5 | ||
|
|
dd680c8a9a | ||
|
|
c92baf6cda | ||
|
|
86afea9b4e | ||
|
|
4568427c66 | ||
|
|
19c79d0374 | ||
|
|
0cdc2dc3d8 | ||
|
|
2a6ec3cd1b | ||
|
|
1599284334 | ||
|
|
2345c5453f |
No files matched your search
-129
@@ -1,129 +0,0 @@
|
||||
#!/usr/bin/php
|
||||
<?php
|
||||
|
||||
array_shift($argv);
|
||||
|
||||
$opt = getopt('c::f:v', [ 'folder:', 'confirm', 'verbose', 'clean', 'old' ]);
|
||||
|
||||
if ( ! $opt ) {
|
||||
exit("Bad arguments provided, you must specify a fullpath using the -f or --folder option\n");
|
||||
}
|
||||
|
||||
$iterator = new RecursiveIteratorIterator(new class(new RecursiveDirectoryIterator($opt['folder'] ?? $opt['f'], FilesystemIterator::SKIP_DOTS)) extends RecursiveFilterIterator {
|
||||
public function accept() : bool {
|
||||
return true;
|
||||
}
|
||||
}, RecursiveIteratorIterator::SELF_FIRST);
|
||||
|
||||
$files = array();
|
||||
|
||||
foreach ($iterator as $info) {
|
||||
if ($info->getExtension() !== "php" || $info->isDir() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
echo sprintf("\n### MIGRATING FILE %s\n", $info->getFilename());
|
||||
|
||||
$opened = false;
|
||||
|
||||
$attr = $newContent = [];
|
||||
|
||||
$content = file_get_contents($info->getPathname());
|
||||
|
||||
if ( isset($opt['clean']) ) {
|
||||
foreach (explode(PHP_EOL, $content) as $lineIdx => $line) {
|
||||
if ( $pos = strpos($line, '# migrated from: ') ) {
|
||||
$attr = true;
|
||||
|
||||
$newContent[] = $newLine = substr($line, 0, $pos);
|
||||
|
||||
echo sprintf("Changed line '%s' \n", trim($newLine));
|
||||
}
|
||||
else {
|
||||
$newContent[] = $line;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
foreach (explode(PHP_EOL, $content) as $lineIdx => $line) {
|
||||
$tline = trim($line);
|
||||
|
||||
if ($tline === "/**") {
|
||||
$opened = true;
|
||||
} elseif ($tline === '*/') {
|
||||
$opened = false;
|
||||
} elseif (substr($tline, 0, 1) === '*') {
|
||||
$annotation = trim(substr($tline, 1));
|
||||
|
||||
if (strpos($annotation, '@') === 0) {
|
||||
$argpos = strpos($annotation, '(');
|
||||
|
||||
if ($argpos !== false) {
|
||||
$name = substr($annotation, 1, $argpos - 1);
|
||||
$args = substr($annotation, $argpos + 1, strrpos($annotation, ')') - $argpos - 1);
|
||||
|
||||
try {
|
||||
$array = eval("return [{$args}];");
|
||||
|
||||
$renderedArgs = [];
|
||||
|
||||
foreach ($array as $key => $argument) {
|
||||
|
||||
if (is_array($argument)) {
|
||||
$argument = var_export($argument, true);
|
||||
} elseif (is_bool($argument)) {
|
||||
$argument = $argument ? 'true' : 'false';
|
||||
} elseif (!is_numeric($argument)) {
|
||||
$argument = "\"$argument\"";
|
||||
}
|
||||
|
||||
if (is_numeric($key)) {
|
||||
$renderedArgs[] = $argument;
|
||||
} else {
|
||||
$renderedArgs[] = "$key: $argument";
|
||||
}
|
||||
}
|
||||
|
||||
$renderedArgs = implode(', ', $renderedArgs);
|
||||
} catch (\Throwable $e) {
|
||||
echo sprintf("!!! WARNING : %s in file (%s) line %d ; using previous notation.\n", $e->getMessage(), $info->getPathname(), $lineIdx + 1);
|
||||
|
||||
$renderedArgs = str_replace(' => ', ': ', $args);
|
||||
}
|
||||
} else {
|
||||
$name = substr($annotation, 1);
|
||||
$renderedArgs = "";
|
||||
}
|
||||
|
||||
$attr[] = $attribute = sprintf("%s#[%s%s]%s", str_repeat(" ", strlen($line) - strlen(ltrim($line)) >= 4 ? 4 : 0), $name, $renderedArgs ? "($renderedArgs)" : "", $renderedArgs ? ( isset($opt['old']) ? " # migrated from: $args" : "" ) : "");
|
||||
|
||||
$newContent[] = $attribute;
|
||||
}
|
||||
} else {
|
||||
$newContent[] = $line;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$newContent = implode(PHP_EOL, $newContent);
|
||||
|
||||
if ($attr) {
|
||||
if ( isset($opt['verbose']) || isset($opt['v']) ) {
|
||||
echo $newContent;
|
||||
}
|
||||
|
||||
if ( isset($opt['confirm']) || isset($opt['c']) ) {
|
||||
file_put_contents($info->getPathname(), $newContent);
|
||||
|
||||
echo sprintf("\n### FILE CONVERSION COMPLETED %s\n", $info->getFilename());
|
||||
}
|
||||
else {
|
||||
echo sprintf("\n### FILE CONVERSION ANALYZED, NOTHING WRITTEN UNTIL --confirm or -c FLAG IS PROVIDED %s\n", $info->getFilename());
|
||||
}
|
||||
}
|
||||
else {
|
||||
echo sprintf("\n### NOTHING TO DO ON FILE %s\n", $info->getFilename());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -99,6 +99,8 @@ class AnnotationReader
|
||||
case $reflect instanceof ReflectionClass :
|
||||
return $reflect->name;
|
||||
}
|
||||
|
||||
return "#UNKNOWN#";
|
||||
}
|
||||
|
||||
protected function getObjectNamespace(Reflector $reflect) : string
|
||||
|
||||
@@ -33,8 +33,9 @@ class AttributeReader
|
||||
{
|
||||
switch(true) {
|
||||
case $reflect instanceof ReflectionMethod :
|
||||
case $reflect instanceof ReflectionProperty :
|
||||
return $reflect->class . "::" . $reflect->name;
|
||||
case $reflect instanceof ReflectionProperty :
|
||||
return $reflect->class . "::$" . $reflect->name;
|
||||
|
||||
case $reflect instanceof ReflectionClass :
|
||||
return $reflect->name;
|
||||
|
||||
@@ -10,6 +10,8 @@ use RuntimeException, DirectoryIterator, Generator;
|
||||
|
||||
class Breadcrumb extends RouteFetcher {
|
||||
|
||||
public bool $ignoreSoleRoute = true;
|
||||
|
||||
public function getRouteTree(\Notes\Route\Attribute\Method\Route $route) : array
|
||||
{
|
||||
$tree = [];
|
||||
@@ -36,7 +38,11 @@ class Breadcrumb extends RouteFetcher {
|
||||
else {
|
||||
$route = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if ($this->ignoreSoleRoute && count($tree) === 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_reverse($tree);
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ class CommandFetcher {
|
||||
|
||||
$class = $this->generateClassname($basename, $namespace);
|
||||
|
||||
$objectResolver = new ObjectResolver($class, true, false, false);
|
||||
$objectResolver = new ObjectResolver($class, $this->cache);
|
||||
|
||||
$attributes = $objectResolver->getAttributeListFromClassname( $this->annotations['object'], false ) ;
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ abstract class Reflected
|
||||
$type = strtolower($type);
|
||||
|
||||
foreach($this->getTypes() as $item) {
|
||||
|
||||
if ($type === "null") {
|
||||
if ($item->type === "null" || $item->nullable) {
|
||||
return true;
|
||||
@@ -46,6 +45,8 @@ abstract class Reflected
|
||||
$type = $property->getType();
|
||||
|
||||
if ($type instanceof \ReflectionUnionType ) {
|
||||
$this->type = [];
|
||||
|
||||
foreach($type->getTypes() as $item) {
|
||||
$this->type[] = new ReflectedPropertyType($item->getName(), $item->isBuiltIn(), $item->allowsNull());
|
||||
}
|
||||
@@ -56,4 +57,27 @@ abstract class Reflected
|
||||
}
|
||||
}
|
||||
|
||||
public function getAttributes(null|string|array $attributeType = null): array
|
||||
{
|
||||
if ($attributeType) {
|
||||
$list = [];
|
||||
|
||||
foreach($this->attributes as $attribute) {
|
||||
foreach((array) $attributeType as $type) {
|
||||
if ($attribute->object instanceof $type) {
|
||||
$list[] = $attribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_reverse($list);
|
||||
}
|
||||
|
||||
return array_reverse($this->attributes);
|
||||
}
|
||||
|
||||
public function getAttribute(string|array $attributeType): ?object
|
||||
{
|
||||
return $this->getAttributes($attributeType)[0] ?? null;
|
||||
}
|
||||
}
|
||||
@@ -14,10 +14,16 @@ class ReflectedClass implements ReflectedInterface
|
||||
public array $traits = [],
|
||||
) {}
|
||||
|
||||
public function getClassName() : string
|
||||
{
|
||||
$exploded = explode('\\', $this->name);
|
||||
|
||||
return end($exploded);
|
||||
}
|
||||
|
||||
public function getProperties(bool $deep = true) : array
|
||||
{
|
||||
return $deep ? array_replace(
|
||||
# $this->parent ? $this->parent->getProperties(true) : [],
|
||||
$this->parent ? $this->parent->getProperties(true) : [],
|
||||
$this->properties
|
||||
) : $this->properties;
|
||||
@@ -35,14 +41,33 @@ class ReflectedClass implements ReflectedInterface
|
||||
) : $this->methods;
|
||||
}
|
||||
|
||||
public function getAttributes(bool $deep = true) : array
|
||||
public function getAttributes(bool $deep = true, ? string $attributeType = null) : array
|
||||
{
|
||||
return $deep ? array_merge(
|
||||
$this->parent ? $this->parent->getAttributes(true) : [],
|
||||
array_merge(...array_map(fn($e) => $e->getAttributes(true), $this->interfaces)),
|
||||
array_merge(...array_map(fn($e) => $e->getAttributes(true), $this->traits)),
|
||||
return array_reverse($this->getOrderedAttributes($deep, $attributeType));
|
||||
}
|
||||
|
||||
protected function getOrderedAttributes(bool $deep = true, ? string $attributeType = null) : array
|
||||
{
|
||||
$attributes = $deep ? array_merge(
|
||||
$this->parent ? $this->parent->getOrderedAttributes(true) : [],
|
||||
array_merge(...array_map(fn($e) => $e->getOrderedAttributes(true), $this->interfaces)),
|
||||
array_merge(...array_map(fn($e) => $e->getOrderedAttributes(true), $this->traits)),
|
||||
$this->attributes
|
||||
) : $this->attributes;
|
||||
|
||||
if ($attributeType) {
|
||||
$list = [];
|
||||
|
||||
foreach($attributes as $attribute) {
|
||||
if ($attribute->object instanceof $attributeType) {
|
||||
$list[] = $attribute;
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
# Get Attributes based on Native attributes's target
|
||||
@@ -146,4 +171,13 @@ class ReflectedClass implements ReflectedInterface
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function getAttribute(string $attributeType): ?object
|
||||
{
|
||||
foreach($this->getAttributes(true, $attributeType) as $attribute) {
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,4 @@ class ReflectedMethod extends Reflected implements ReflectedInterface
|
||||
public array $parameters = [],
|
||||
) {}
|
||||
|
||||
public function getAttributes(): array
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
}
|
||||
@@ -14,12 +14,6 @@ class ReflectedProperty extends Reflected implements ReflectedInterface, \ArrayA
|
||||
public array $attributes = [],
|
||||
) {}
|
||||
|
||||
public function getAttributes(): array
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
|
||||
## BACKWARD COMPATIBILITY ONLY To be removed really soon !
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
|
||||
@@ -18,4 +18,14 @@ class ReflectedPropertyType
|
||||
|
||||
return $this->type === $type;
|
||||
}
|
||||
|
||||
public function isObject() : bool
|
||||
{
|
||||
return ! $this->builtIn && class_exists($this->type);
|
||||
}
|
||||
|
||||
public function isEnum() : bool
|
||||
{
|
||||
return ! $this->builtIn && enum_exists($this->type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Notes\Common;
|
||||
|
||||
class ReflectedPropertyType
|
||||
{
|
||||
public function __construct(
|
||||
public string $type,
|
||||
public bool $builtIn,
|
||||
public bool $nullable,
|
||||
) {}
|
||||
|
||||
public function isType(string $type) : bool
|
||||
{
|
||||
if ($type === "null" || $this->nullable) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->type === $type;
|
||||
}
|
||||
|
||||
public function isObject() : bool
|
||||
{
|
||||
return ! $this->builtIn && class_exists($this->type);
|
||||
}
|
||||
}
|
||||
@@ -7,5 +7,6 @@ class Cronard implements \Notes\Attribute {
|
||||
public function __construct(
|
||||
public string $cron,
|
||||
public null|string $method = null,
|
||||
public null|string $name = null,
|
||||
) {}
|
||||
}
|
||||
+16
-16
@@ -23,15 +23,17 @@ class ObjectReflection {
|
||||
$this->classname = ltrim($class instanceof ReflectionClass ? $class->getName() : $class, '\\');
|
||||
|
||||
$this->cache = $cache;
|
||||
|
||||
#if ( ! $this->cache || ! $this->cache->has($class) ) {
|
||||
$this->classReflection = $class instanceof ReflectionClass ? $class : new ReflectionClass($class);
|
||||
# }
|
||||
$this->classReflection = $class instanceof ReflectionClass ? $class : new ReflectionClass($class);
|
||||
}
|
||||
|
||||
public static function fromClass(ReflectionClass|string $class, ? CacheInterface $cache = null) : self
|
||||
{
|
||||
return new static($class, null, $cache);
|
||||
return new static($class, $cache);
|
||||
}
|
||||
|
||||
public function getClassReflection() : ReflectionClass
|
||||
{
|
||||
return $this->classReflection;
|
||||
}
|
||||
|
||||
public function reflectClass() : ReflectedClass
|
||||
@@ -48,11 +50,11 @@ class ObjectReflection {
|
||||
traits: array_map(fn($trait) => static::fromClass($trait)->reflectClass(), array_keys($this->classReflection->getTraits())),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function reflectProperties(int $filter =
|
||||
ReflectionProperty::IS_PUBLIC |
|
||||
ReflectionProperty::IS_PROTECTED |
|
||||
ReflectionProperty::IS_PRIVATE
|
||||
ReflectionProperty::IS_PUBLIC |
|
||||
ReflectionProperty::IS_PROTECTED |
|
||||
ReflectionProperty::IS_PRIVATE
|
||||
) : array
|
||||
{
|
||||
$defaultValues = $this->classReflection->getDefaultProperties();
|
||||
@@ -61,7 +63,6 @@ class ObjectReflection {
|
||||
|
||||
foreach($this->classReflection->getProperties($filter) as $property) {
|
||||
$reflected = new ReflectedProperty($property->getName());
|
||||
|
||||
$reflected->attributes = AttributeReader::reflectAttributes($property);
|
||||
|
||||
if ( $reflected->hasIgnoreAttribute() ) {
|
||||
@@ -82,18 +83,17 @@ class ObjectReflection {
|
||||
}
|
||||
|
||||
public function reflectMethods(int $filter =
|
||||
ReflectionMethod::IS_PUBLIC |
|
||||
ReflectionMethod::IS_PROTECTED |
|
||||
ReflectionMethod::IS_PRIVATE |
|
||||
ReflectionMethod::IS_STATIC |
|
||||
ReflectionMethod::IS_FINAL
|
||||
ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED |
|
||||
ReflectionMethod::IS_PRIVATE | ReflectionMethod::IS_STATIC |
|
||||
ReflectionMethod::IS_FINAL,
|
||||
bool $includeParents = false
|
||||
) : array
|
||||
{
|
||||
$list = [];
|
||||
|
||||
foreach($this->classReflection->getMethods($filter) as $method) {
|
||||
# Skipping parent's methods, we'll retrieve them in its own reflection
|
||||
if ( $method->class !== $this->classname ) {
|
||||
if ( ! $includeParents && $method->class !== $this->classname ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Notes\Route\Attribute\Method;
|
||||
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
#[\Attribute(\Attribute::IS_REPEATABLE | \Attribute::TARGET_METHOD)]
|
||||
class Route implements \Notes\Attribute {
|
||||
public function __construct(
|
||||
@@ -12,8 +14,14 @@ class Route implements \Notes\Attribute {
|
||||
public ? string $class = null,
|
||||
public ? string $classMethod = null,
|
||||
public bool $currentRoute = false,
|
||||
public string $description = "",
|
||||
) {}
|
||||
|
||||
public function getBase() : ?string
|
||||
{
|
||||
return $this->base ? rtrim($this->base, '/') : null;
|
||||
}
|
||||
|
||||
public function getRoute() : string
|
||||
{
|
||||
return rtrim("/" . trim(isset($this->base) ?
|
||||
@@ -22,11 +30,28 @@ class Route implements \Notes\Attribute {
|
||||
"/" . ltrim($this->route, "/"), "/"), '/');
|
||||
}
|
||||
|
||||
public function getRegistrableRoute() : string
|
||||
{
|
||||
return preg_replace('/(\=.*)(?=\})/i', '', $this->getRoute());
|
||||
}
|
||||
|
||||
public function matchRouteName(string $name) : bool
|
||||
{
|
||||
return strtolower($this->name) === strtolower($name);
|
||||
}
|
||||
|
||||
|
||||
public function match(mixed $name) : bool
|
||||
{
|
||||
foreach((array) $name as $item) {
|
||||
if ( fnmatch($item, $this->name) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isRoute(string $name) {
|
||||
return $this->name === $name;
|
||||
}
|
||||
|
||||
@@ -8,5 +8,11 @@ class Route implements \Notes\Attribute {
|
||||
public string|array $method = [ "GET", "POST" ],
|
||||
# NULL will fallback on nearest base
|
||||
public null|string $base = null,
|
||||
public null|bool $inheritRoutes = null, # true or false will skip others attribute from parents after, null = skipped for this one.
|
||||
){}
|
||||
|
||||
public function getBase() : ?string
|
||||
{
|
||||
return $this->base ? rtrim($this->base, '/') : null;
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,14 @@ class RouteFetcher {
|
||||
{
|
||||
$attributes ??= $this->attributes;
|
||||
|
||||
/*
|
||||
8.5: return $attributes
|
||||
|> serialize(...)
|
||||
|> md5(...)
|
||||
|> (fn($x) => substr($x, 0, 7))
|
||||
|> (fn($x) => $this->handleCaching())
|
||||
*/
|
||||
|
||||
return $this->handleCaching(substr(md5(serialize($attributes)), 0, 7), function() use ($attributes) : array {
|
||||
$list = [];
|
||||
|
||||
@@ -92,24 +100,27 @@ class RouteFetcher {
|
||||
$base = null;
|
||||
$class = $this->generateClassname($file->getBasename(".php"), $namespace);
|
||||
$methods = null;
|
||||
$inheritRoutes = null;
|
||||
|
||||
$objectResolver = new ObjectResolver($class, $this->cache);
|
||||
|
||||
if ( isset($attributes['object']) ) {
|
||||
|
||||
# Also loading Routes attribute from parent classes
|
||||
$objects = $objectResolver->reflectedClass->getClassAttributeListFromClassname($attributes['object'], true, false);
|
||||
|
||||
foreach(array_reverse($objects) as $object) {
|
||||
foreach($objects as $object) {
|
||||
if ($object->method ?? false ) {
|
||||
$methods ??= (array) $object->method;
|
||||
}
|
||||
|
||||
$inheritRoutes ??= $object->inheritRoutes;
|
||||
$base ??= $object->base ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset($attributes['method']) ) {
|
||||
$routeList = $objectResolver->reflectedClass->getMethodAttributeListFromClassname( $attributes['method'], false, false );
|
||||
$routeList = $objectResolver->reflectedClass->getMethodAttributeListFromClassname( $attributes['method'], (bool) $inheritRoutes, false );
|
||||
|
||||
foreach($routeList as $func => $routes) {
|
||||
if (is_array($routes)) {
|
||||
@@ -118,12 +129,10 @@ class RouteFetcher {
|
||||
if ($route instanceof \Notes\Route\Attribute\Method\Route) {
|
||||
$route->base = $route->base ?: $base;
|
||||
}
|
||||
|
||||
$route->class = $class;
|
||||
$route->classMethod = $func;
|
||||
|
||||
if (false === ($route->methods ?? false)) {
|
||||
$route->methods = $methods ?? $this->defaultMethods;
|
||||
}
|
||||
$route->method ??= $methods ?? $this->defaultMethods;
|
||||
|
||||
if (false !== ($this->callback ?? false)) {
|
||||
call_user_func_array($this->callback, [$route]);
|
||||
|
||||
@@ -7,5 +7,6 @@ class Taxus implements \Notes\Attribute {
|
||||
public function __construct(
|
||||
public null|string|\BackedEnum $privilege = null,
|
||||
public null|string $module = null,
|
||||
public string|array $method = "*",
|
||||
) {}
|
||||
}
|
||||
@@ -2,21 +2,23 @@
|
||||
|
||||
namespace Notes\Security;
|
||||
|
||||
use Notes\Common\ReflectedAttribute;
|
||||
use Taxus\Taxus;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
use Notes\ObjectResolver;
|
||||
use Taxus\TaxusGrantEnum;
|
||||
|
||||
class SecurityHandler {
|
||||
|
||||
protected ResponseInterface $redirectResponse;
|
||||
|
||||
protected ? \Closure $unauthorizeResponse;
|
||||
protected \Closure|ResponseInterface|null $unauthorizeResponse;
|
||||
|
||||
protected ? Taxus $taxus;
|
||||
|
||||
public function __construct(ResponseInterface $redirectResponse, ? \Closure $unauthorizeResponse = null, ? Taxus $taxus = null) {
|
||||
public function __construct(ResponseInterface $redirectResponse, \Closure|ResponseInterface|null $unauthorizeResponse = null, ? Taxus $taxus = null) {
|
||||
$this->redirectResponse = $redirectResponse;
|
||||
$this->unauthorizeResponse = $unauthorizeResponse;
|
||||
$this->taxus = $taxus;
|
||||
@@ -27,51 +29,88 @@ class SecurityHandler {
|
||||
return $this->isLocked($className, $methodName) ? $this->redirectResponse : null;
|
||||
}
|
||||
|
||||
# @TODO Must HANDLE REALM !
|
||||
public function isLocked(string $className, string $methodName) : bool
|
||||
{
|
||||
if ( $security = $this->getClassAttributes(Attribute\Security::class, $className, $methodName) ) {
|
||||
return array_pop($security)->locked;
|
||||
# Searching method first and fallbacking on object if none found
|
||||
if ( $list = $this->findAttributes(Attribute\Security::class, $className, $methodName) ) {
|
||||
return array_shift($list)->locked;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function taxus(string $className, string $methodName, object $user = null) : ? ResponseInterface
|
||||
public function taxus(string $className, string $methodName, ... $arguments) : ? ResponseInterface
|
||||
{
|
||||
if ($taxus = $this->getClassAttributes(Attribute\Taxus::class, $className, $methodName)) {
|
||||
$granted = $this->hasGrantPermission($className , $methodName, ...$arguments);
|
||||
|
||||
if ($granted) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
if ($this->unauthorizeResponse) {
|
||||
foreach ($taxus as $item) {
|
||||
if (!isset($item->privilege) || $this->taxus->granted($item->privilege, $user, $item)) {
|
||||
return null;
|
||||
}
|
||||
if ($this->unauthorizeResponse instanceof ResponseInterface) {
|
||||
return $this->unauthorizeResponse;
|
||||
}
|
||||
|
||||
return call_user_func_array($this->unauthorizeResponse, [ $user, $taxus, $className, $methodName ]);
|
||||
return call_user_func_array($this->unauthorizeResponse, [ ...$arguments, ['method' => $methodName, 'object' => $className ], $className, $methodName ]);
|
||||
}
|
||||
else {
|
||||
throw new \ErrorException("Unauthorized response given.");
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function getClassAttributes(string $annotationClass, string $className, string $methodName)/* : \Notes\Attribute|array */
|
||||
public function hasGrantPermission(string $className, string $methodName, ... $arguments) : bool
|
||||
{
|
||||
$objectResolver = new ObjectResolver($className);
|
||||
$fromObject = $this->findAttributes(Attribute\Taxus::class, $className);
|
||||
$fromMethod = $this->findAttributes(Attribute\Taxus::class, $className, $methodName);
|
||||
|
||||
try {
|
||||
$method = $objectResolver->reflectedClass->getClassAttributeList( $annotationClass, true, false );
|
||||
if ($fromMethod) {
|
||||
return $this->taxusGrantPermission($fromMethod, ... $arguments);
|
||||
}
|
||||
elseif ($fromObject) {
|
||||
return $this->taxusGrantPermission($fromObject, ... $arguments);
|
||||
}
|
||||
|
||||
# var_dump($method);
|
||||
}
|
||||
catch(\Exception $e) { }
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( $method[$methodName] ?? false ) {
|
||||
return $method[$methodName];
|
||||
protected function findAttributes(string $attribute, string $class, ? string $method = null) : array
|
||||
{
|
||||
$objectResolver = new ObjectResolver($class);
|
||||
|
||||
if ($method) {
|
||||
$fromMethod = $objectResolver->reflectedClass->getMethods( false );
|
||||
|
||||
if (isset($fromMethod[$method])) {
|
||||
$attributeList = $fromMethod[$method]->getAttributes($attribute);
|
||||
|
||||
if ($attributeList) {
|
||||
return array_map(fn(ReflectedAttribute $ref) => $ref->object, $attributeList);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
return array_filter($method, fn($e) => is_object($e));
|
||||
|
||||
$attributeList = $objectResolver->reflectedClass->getAttributes(false, $attribute) ?: $objectResolver->reflectedClass->getAttributes(true, $attribute);
|
||||
|
||||
if ($attributeList) {
|
||||
return array_map(fn(ReflectedAttribute $ref) => $ref->object, $attributeList);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function taxusGrantPermission(array $attributeList, ...$arguments) : bool
|
||||
{
|
||||
foreach ($attributeList as $item) {
|
||||
if ( $grant = $this->taxus->granted($item->privilege, ... array_merge($arguments, [ $item ])) ) {
|
||||
if (is_bool($grant) ? $grant : $grant === TaxusGrantEnum::Authorized) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user