- WIP on Attributes conversion from annotations

This commit is contained in:
Dave M. 2023-01-21 18:37:54 +00:00
parent f4fffbd480
commit a876ea9045
2 changed files with 242 additions and 33 deletions

120
bin/migrate.php Executable file
View File

@ -0,0 +1,120 @@
#!/usr/bin/php
<?php
array_shift($argv);
$opt = getopt('c::f:v', [ 'folder:', 'confirm', 'verbose' ]);
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());
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", $name, $renderedArgs ? "($renderedArgs)" : "", $renderedArgs ? " # 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());
}
}

View File

@ -28,59 +28,60 @@ class ObjectResolver {
$this->resolveAnnotations(); $this->resolveAnnotations();
} }
/** /**
* Transform an annotation into it's object's counterpart * Transform an annotation into it's object's counterpart
*/ */
public function getAnnotationFromClassname(string $className) : ? object public function getAttributeFromClassname(array|string $className, bool $throwOnError = true) : object|bool
{ {
if ( $name = $this->uses[$className] ?? false) { foreach((array) $className as $class) {
foreach(array_reverse($this->class['tags']) as $item) { foreach (array_reverse($this->class['tags']) as $item) {
if ( $item['tag'] === $name ) { if ($item['object'] instanceof $class) {
return $this->instanciateAnnotationObject($item); return $this->instanciateAnnotationObject($item);
} }
foreach($this->properties as $property) { foreach ($this->properties as $property) {
foreach($property['tags'] as $item) { foreach ($property['tags'] as $tag) {
if ( $item['tag'] === $name ) { if ($item['object'] instanceof $class) {
return $this->instanciateAnnotationObject($item); return $this->instanciateAnnotationObject($tag);
} }
} }
} }
foreach($this->methods as $method) { foreach ($this->methods as $method) {
foreach($method['tags'] as $item) { foreach ($method['tags'] as $tag) {
if ( $item['tag'] === $name ) { if ($item['object'] instanceof $class) {
return $this->instanciateAnnotationObject($item); return $this->instanciateAnnotationObject($tag);
} }
} }
} }
} }
throw new \Exception("Annotation `$className` could not be found within your object `{$this->objectClass}`");
}
else {
throw new \InvalidArgumentException("Class `$className` was not found within {$this->objectClass} uses statement (or it's children / traits)");
} }
return null; if ($throwOnError) {
throw new \Exception(sprintf("Annotation `%s` could not be found within your object `%s`.", implode(', ', (array)$className), $this->objectClass));
}
return false;
} }
/** /**
* Transform an annotation into it's object's counterpart * Transform an annotation into it's object's counterpart
*/ */
public function getAnnotationListFromClassname(string $className, bool $throwOnError = true) : array public function getAttributeListFromClassname(array|string $className, bool $throwOnError = true) : array
{ {
$list = []; $list = [];
if ( $name = $this->uses[$className] ?? false) { foreach((array) $className as $class) {
foreach($this->class['tags'] as $item) { foreach ($this->class['tags'] as $item) {
if ($item['tag'] === $name) { if ($item['object'] instanceof $class) {
$list[] = $this->instanciateAnnotationObject($item); $list[] = $this->instanciateAnnotationObject($item);
} }
} }
foreach($this->properties as $property) { foreach ($this->properties as $property) {
foreach($property['tags'] as $item) { foreach ($property['tags'] as $item) {
if ( $item['tag'] === $name ) { if ($item['object'] instanceof $class) {
$list[$property['name']] ??= []; $list[$property['name']] ??= [];
$list[$property['name']][] = $this->instanciateAnnotationObject($item); $list[$property['name']][] = $this->instanciateAnnotationObject($item);
@ -88,17 +89,101 @@ class ObjectResolver {
} }
} }
foreach($this->methods as $method) { foreach ($this->methods as $method) {
foreach($method['tags'] as $item) { foreach ($method['tags'] as $item) {
if ( $item['tag'] === $name ) { if ($item['object'] instanceof $class) {
$list[$method['name']] ??= []; $list[$method['name']] ??= [];
$list[$method['name']][] = $this->instanciateAnnotationObject($item); $list[$method['name']][] = $this->instanciateAnnotationObject($item);
} }
} }
} }
} }
else {
if ( empty($list) ) {
if ($throwOnError) throw new \InvalidArgumentException("Class `$className` was not found within {$this->objectClass} uses statement (or it's children / traits)");
}
return $list;
}
/**
* @deprecated Will soon be deprecated in favour of PHP's native attributes
* Transform an annotation into it's object's counterpart
*/
public function getAnnotationFromClassname(array|string $className, bool $throwOnError = true) : object|bool
{
foreach((array) $className as $class) {
if ( $name = $this->uses[$class] ?? false) {
foreach (array_reverse($this->class['tags']) as $item) {
if ($item['tag'] === $name) {
return $this->instanciateAnnotationObject($item);
}
foreach ($this->properties as $property) {
foreach ($property['tags'] as $item) {
if ($item['tag'] === $name) {
return $this->instanciateAnnotationObject($item);
}
}
}
foreach ($this->methods as $method) {
foreach ($method['tags'] as $item) {
if ($item['tag'] === $name) {
return $this->instanciateAnnotationObject($item);
}
}
}
}
}
}
if ($throwOnError) {
throw new \Exception(sprintf("Annotation `%s` could not be found within your object `%s`.", implode(', ', (array)$className), $this->objectClass));
}
return false;
}
/**
* Transform an annotation into it's object's counterpart
*/
public function getAnnotationListFromClassname(array|string $className, bool $throwOnError = true) : array
{
$list = [];
foreach((array) $className as $class) {
if ($name = $this->uses[$class] ?? false) {
foreach ($this->class['tags'] as $item) {
if ($item['tag'] === $name) {
$list[] = $this->instanciateAnnotationObject($item);
}
}
foreach ($this->properties as $property) {
foreach ($property['tags'] as $item) {
if ($item['tag'] === $name) {
$list[$property['name']] ??= [];
$list[$property['name']][] = $this->instanciateAnnotationObject($item);
}
}
}
foreach ($this->methods as $method) {
foreach ($method['tags'] as $item) {
if ($item['tag'] === $name) {
$list[$method['name']] ??= [];
$list[$method['name']][] = $this->instanciateAnnotationObject($item);
}
}
}
}
}
if ( empty($list) ) {
if ($throwOnError) throw new \InvalidArgumentException("Class `$className` was not found within {$this->objectClass} uses statement (or it's children / traits)"); if ($throwOnError) throw new \InvalidArgumentException("Class `$className` was not found within {$this->objectClass} uses statement (or it's children / traits)");
} }
@ -107,6 +192,10 @@ class ObjectResolver {
public function instanciateAnnotationObject(array $tagDefinition) : Annotation public function instanciateAnnotationObject(array $tagDefinition) : Annotation
{ {
if (isset($tagDefinition['object']) && $tagDefinition['object'] instanceof \Attribute) {
return $tagDefinition['object'];
}
$arguments = $this->extractArguments($tagDefinition['arguments']); $arguments = $this->extractArguments($tagDefinition['arguments']);
if ( false === $class = array_search($tagDefinition['tag'], $this->uses) ) { if ( false === $class = array_search($tagDefinition['tag'], $this->uses) ) {
@ -145,18 +234,18 @@ class ObjectResolver {
protected function resolveAnnotations() protected function resolveAnnotations()
{ {
foreach($this->class['tags'] as $key => &$tag) { foreach($this->class['tags'] as $key => &$tag) {
$tag['object'] = $this->instanciateAnnotationObject($tag); $tag['object'] ??= $this->instanciateAnnotationObject($tag);
} }
foreach($this->properties as &$property) { foreach($this->properties as &$property) {
foreach($property['tags'] as &$tag){ foreach($property['tags'] as &$tag){
$tag['object'] = $this->instanciateAnnotationObject($tag); $tag['object'] ??= $this->instanciateAnnotationObject($tag);
} }
} }
foreach($this->methods as &$method) { foreach($this->methods as &$method) {
foreach($method['tags'] as &$tag){ foreach($method['tags'] as &$tag){
$tag['object'] = $this->instanciateAnnotationObject($tag); $tag['object'] ??= $this->instanciateAnnotationObject($tag);
} }
} }
} }