- Prepping 8.1 migration

This commit is contained in:
Dave M. 2022-07-18 16:18:29 +00:00
parent 00ebf3381f
commit e97df353ae
18 changed files with 18 additions and 392 deletions

View File

@ -1,5 +0,0 @@
<?php
namespace Ulmus\Annotation;
interface Annotation {}

View File

@ -1,103 +0,0 @@
<?php
namespace Ulmus\Annotation;
use Reflector, ReflectionClass, ReflectionProperty, ReflectionMethod;
/**
* This class exists while waiting for the official RFC [ https://wiki.php.net/rfc/annotations_v2 ]
*/
class AnnotationReader
{
const PHP_TYPES = [ "string", "int", "float", "object", "double", "closure", ];
public string $class;
public function __construct($class) {
$this->class = $class;
}
public static function fromClass($class) : self
{
return new static($class);
}
public function getProperty(ReflectionProperty $property)
{
return $this->parseDocComment($property);
}
public function getClass(ReflectionClass $class)
{
return $this->parseDocComment($class);
}
public function getMethod(ReflectionMethod $method)
{
return $this->parseDocComment($method);
}
protected function parseDocComment(Reflector $reflect)
{
$namespace = $this->getObjectNamespace($reflect);
$tags = [];
foreach(preg_split("/\r\n|\n|\r/", $reflect->getDocComment()) as $line) {
$line = ltrim($line, "* \t\/");
$line = rtrim($line, "\t ");
if ( substr($line, 0, 1) === '@' ) {
$line = ltrim($line, '@');
$open = strpos($line, "(");
$close = strrpos($line, ")");
if ( ! in_array(false, [ $open, $close ], true) && ( ++$open !== $close ) ) {
$arguments = substr($line, $open, $close - $open);
try {
$tags[] = [
'tag' => substr($line, 0, $open - 1),
'arguments' => eval("namespace $namespace; return [ $arguments ];" ),
];
}
catch(\Throwable $error) {
throw new \InvalidArgumentException("An error occured while parsing annotation from '" . $this->getObjectName($reflect) . "' : @$line -- " . $error->getMessage());
}
}
else {
$tags[] = [
'tag' => $line,
'arguments' => [],
];
}
}
}
return $tags;
}
protected function getObjectName(Reflector $reflect) : string
{
switch(true) {
case $reflect instanceof ReflectionMethod :
case $reflect instanceof ReflectionProperty :
return $reflect->class . "::" . $reflect->name;
case $reflect instanceof ReflectionClass :
return $reflect->name;
}
}
protected function getObjectNamespace(Reflector $reflect) : string
{
switch(true) {
case $reflect instanceof ReflectionMethod :
case $reflect instanceof ReflectionProperty :
return $reflect->getDeclaringClass()->getNamespaceName();
case $reflect instanceof ReflectionClass :
return $reflect->getNamespaceName();
}
}
}

View File

@ -2,6 +2,6 @@
namespace Ulmus\Annotation\Classes;
class Collation implements \Ulmus\Annotation\Annotation {
class Collation implements \Notes\Annotation {
}

View File

@ -2,6 +2,6 @@
namespace Ulmus\Annotation\Classes;
class Method implements \Ulmus\Annotation\Annotation {
class Method implements \Notes\Annotation {
}

View File

@ -2,7 +2,7 @@
namespace Ulmus\Annotation\Classes;
class Table implements \Ulmus\Annotation\Annotation {
class Table implements \Notes\Annotation {
public string $name;

View File

@ -2,7 +2,7 @@
namespace Ulmus\Annotation\Property;
class Field implements \Ulmus\Annotation\Annotation {
class Field implements \Notes\Annotation {
public string $type;

View File

@ -2,7 +2,7 @@
namespace Ulmus\Annotation\Property;
class Filter implements \Ulmus\Annotation\Annotation {
class Filter implements \Notes\Annotation {
public string $method;

View File

@ -2,7 +2,7 @@
namespace Ulmus\Annotation\Property;
class FilterJoin implements \Ulmus\Annotation\Annotation {
class FilterJoin implements \Notes\Annotation {
public string $method;

View File

@ -2,7 +2,7 @@
namespace Ulmus\Annotation\Property;
class GroupBy implements \Ulmus\Annotation\Annotation {
class GroupBy implements \Notes\Annotation {
public array $fields = [];

View File

@ -2,7 +2,7 @@
namespace Ulmus\Annotation\Property;
class Join implements \Ulmus\Annotation\Annotation {
class Join implements \Notes\Annotation {
public string $type;

View File

@ -2,7 +2,7 @@
namespace Ulmus\Annotation\Property;
class OrderBy implements \Ulmus\Annotation\Annotation {
class OrderBy implements \Notes\Annotation {
public string $field;

View File

@ -2,7 +2,7 @@
namespace Ulmus\Annotation\Property;
class Relation implements \Ulmus\Annotation\Annotation {
class Relation implements \Notes\Annotation {
public string $type;

View File

@ -2,4 +2,4 @@
namespace Ulmus\Annotation\Property\Relation;
class Ignore implements \Ulmus\Annotation\Annotation {}
class Ignore implements \Notes\Annotation {}

View File

@ -4,7 +4,7 @@ namespace Ulmus\Annotation\Property;
use Ulmus\Query;
class Where implements \Ulmus\Annotation\Annotation {
class Where implements \Notes\Annotation {
public /* stringable */ $field;

View File

@ -2,7 +2,7 @@
namespace Ulmus\Annotation\Property;
class WithJoin implements \Ulmus\Annotation\Annotation {
class WithJoin implements \Notes\Annotation {
protected array $joins;

View File

@ -3,12 +3,15 @@
namespace Ulmus\Common;
use Ulmus\Ulmus,
Ulmus\Annotation\Annotation,
Ulmus\Annotation\Classes\Table,
Ulmus\Annotation\Property\Field,
Ulmus\Annotation\Property\Virtual,
Ulmus\Annotation\Property\Relation;
use Notes\Annotation;
use Notes\ObjectReflection;
class EntityResolver {
const KEY_ENTITY_NAME = 01;

View File

@ -1,269 +0,0 @@
<?php
namespace Ulmus\Common;
use Ulmus\Ulmus;
use Ulmus\Annotation\AnnotationReader;
use Reflector, ReflectionClass, ReflectionProperty, ReflectionMethod, ReflectionUnionType, ReflectionNamedType, ReflectionParameter;
class ObjectReflection {
public AnnotationReader $annotationReader;
public function __construct($class, AnnotationReader $annotationReader = null) {
$this->classReflection = $class instanceof ReflectionClass ? $class : new ReflectionClass($class);
$this->annotationReader = $annotationReader ?: AnnotationReader::fromClass($class);
}
public static function fromClass($class) : self
{
return new static($class);
}
public function read() : array
{
return [
'uses' => $this->gatherUses(true),
'class' => $this->gatherClass(true),
'method' => $this->gatherMethods(true),
'property' => $this->gatherProperties(true),
];
}
public function gatherUses(bool $full = true) : array
{
$list = [];
if ( $full ) {
if ( $parentClass = $this->classReflection->getParentClass() ) {
$list = static::fromClass($parentClass)->gatherUses(true);
}
foreach($this->classReflection->getTraits() as $trait) {
$list = array_merge($list, static::fromClass($trait)->gatherUses(true));
}
}
return array_merge($this->getUsesStatements(), $list);
}
public function gatherClass(bool $full = true) : array
{
$class = [];
if ( $full ) {
if ( $parentClass = $this->classReflection->getParentClass() ) {
$class = static::fromClass($parentClass)->gatherClass(true);
}
$itemName = function($item) {
return $item->getName();
};
}
return array_merge_recursive($class, [
'tags' => $this->annotationReader->getClass($this->classReflection)
] + ( ! $full ? [] : [
'traits' => array_map($itemName, $this->classReflection->getTraits()),
'interfaces' => array_map($itemName, $this->classReflection->getInterfaces()),
]));
}
public function gatherProperties(bool $full = true, int $filter =
ReflectionProperty::IS_PUBLIC |
ReflectionProperty::IS_PROTECTED |
ReflectionProperty::IS_PRIVATE
) : array
{
$properties = [];
$defaultValues = $this->classReflection->getDefaultProperties();
if ( $full ) {
if ( $parentClass = $this->classReflection->getParentClass() ) {
$properties = static::fromClass($parentClass)->gatherProperties($full, $filter);
}
}
$list = [];
foreach($this->classReflection->getProperties($filter) as $property) {
$current = [
'name' => $property->getName()
];
# Default value can be 'null', so isset() it not suitable here
if ( array_key_exists($current['name'], $defaultValues) ) {
$current['value'] = $defaultValues[ $current['name'] ];
}
if ( $property->hasType() ) {
$current['type'] = $property->getType()->getName();
$current['builtin'] = $property->getType()->isBuiltIn();
$current['nullable'] = $property->getType()->allowsNull();
}
$current['tags'] = $this->annotationReader->getProperty($property);
if ( $this->ignoreElementAnnotation($current['tags']) ) {
continue;
}
$list[ $current['name'] ] = $current;
}
return array_merge($properties, $list);
}
public function gatherMethods(bool $full = true, int $filter =
ReflectionMethod::IS_PUBLIC |
ReflectionMethod::IS_PROTECTED |
ReflectionMethod::IS_PRIVATE |
ReflectionMethod::IS_STATIC
) : array
{
$list = $methods = [];
if ( $full ) {
if ( $parentClass = $this->classReflection->getParentClass() ) {
$methods = static::fromClass($parentClass)->gatherMethods($full, $filter);
}
}
foreach($this->classReflection->getMethods($filter) as $method) {
$parameters = [];
foreach($method->getParameters() as $parameter) {
$parameters[$parameter->getName()] = [
'null' => $parameter->allowsNull(),
'position' => $parameter->getPosition(),
'type' => $parameter->hasType() ? $parameter->getType()->getName() : false,
'array' => \Notes\ObjectReflection::isType('array', $parameter),
'callable' => \Notes\ObjectReflection::isType('callable', $parameter),
'optional' => $parameter->isOptional(),
'byReference' => $parameter->isPassedByReference(),
];
}
$current = [
'name' => $method->getName(),
'type' => $method->hasReturnType() ? $method->getReturnType()->getName() : false,
'constructor' => $method->isConstructor(),
'destructor' => $method->isDestructor(),
'parameters' => $parameters,
];
$current['tags'] = $this->annotationReader->getMethod($method);
if ( $this->ignoreElementAnnotation($current['tags']) ) {
continue;
}
$list[ $current['name'] ] = $current;
}
return array_merge($methods, $list);
}
protected function ignoreElementAnnotation($tags) : bool
{
return in_array('IGNORE', array_map('strtoupper', array_column($tags, 'tag') ));
}
protected function readCode() : string
{
static $code = [];
$fileName = $this->classReflection->getFilename();
return $code[$fileName] ?? $code[$fileName] = file_get_contents($fileName);
}
protected function getUsesStatements() : array
{
$uses = [];
$tokens = token_get_all( $c = $this->readCode() );
while ( $token = array_shift($tokens) ) {
if ( is_array($token) ) {
list($token, $value) = $token;
}
switch ($token) {
case T_CLASS:
case T_TRAIT:
case T_INTERFACE:
break 2;
case T_USE:
$isUse = true;
break;
case T_NS_SEPARATOR:
$isNamespace = $isUse;
break;
case T_STRING:
case T_NAME_QUALIFIED:
if ( $isNamespace && $latestString ) {
$statement[] = $latestString;
}
$latestString = $value;
break;
case T_AS:
# My\Name\Space\aClassHere `as` ClassAlias;
$replacedClass = implode("\\", array_merge($statement, [ $latestString ]));
$latestString = null;
break;
case T_WHITESPACE:
case T_COMMENT:
case T_DOC_COMMENT:
break;
case '{':
# opening a sub-namespace -> \My\Name\Space\`{`OneItem, AnotherItem}
if ( $isNamespace ) {
$inNamespace = true;
}
break;
case ';';
case ',':
case '}':
if ( $isUse ) {
if ( $replacedClass ) {
$uses[$replacedClass] = $latestString;
$replacedClass = "";
}
elseif ( $latestString ) {
$uses[implode("\\", array_merge($statement, [ $latestString ]))] = $latestString;
}
}
if ( $inNamespace ) {
$latestString = "";
# \My\Name\Space\{OneItem, AnotherItem`}` <- closing a sub-namespace
if ( $token !== "}" ) {
break;
}
}
case T_OPEN_TAG:
default:
$statement = [];
$latestString = "";
$replacedClass = null;
$isNamespace = $inNamespace = false;
$isUse = ( $isUse ?? false ) && ( $token === ',' );
break;
}
}
return $uses;
}
}

View File

@ -273,7 +273,7 @@ trait EntityTrait {
/**
* @Ignore
*/
public function jsonSerialize()
public function jsonSerialize() : mixed
{
return $this->entityGetDataset();
}