diff --git a/bin/migrate.php b/bin/migrate.php new file mode 100755 index 0000000..6b87215 --- /dev/null +++ b/bin/migrate.php @@ -0,0 +1,120 @@ +#!/usr/bin/php +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()); + } + +} \ No newline at end of file diff --git a/src/ObjectResolver.php b/src/ObjectResolver.php index 8973b58..efd4d57 100644 --- a/src/ObjectResolver.php +++ b/src/ObjectResolver.php @@ -28,59 +28,60 @@ class ObjectResolver { $this->resolveAnnotations(); } + /** * 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_reverse($this->class['tags']) as $item) { - if ( $item['tag'] === $name ) { + foreach((array) $className as $class) { + foreach (array_reverse($this->class['tags']) as $item) { + if ($item['object'] instanceof $class) { return $this->instanciateAnnotationObject($item); } - foreach($this->properties as $property) { - foreach($property['tags'] as $item) { - if ( $item['tag'] === $name ) { - return $this->instanciateAnnotationObject($item); + foreach ($this->properties as $property) { + foreach ($property['tags'] as $tag) { + if ($item['object'] instanceof $class) { + return $this->instanciateAnnotationObject($tag); } } } - foreach($this->methods as $method) { - foreach($method['tags'] as $item) { - if ( $item['tag'] === $name ) { - return $this->instanciateAnnotationObject($item); + foreach ($this->methods as $method) { + foreach ($method['tags'] as $tag) { + if ($item['object'] instanceof $class) { + 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 */ - public function getAnnotationListFromClassname(string $className, bool $throwOnError = true) : array + public function getAttributeListFromClassname(array|string $className, bool $throwOnError = true) : array { $list = []; - if ( $name = $this->uses[$className] ?? false) { - foreach($this->class['tags'] as $item) { - if ($item['tag'] === $name) { + foreach((array) $className as $class) { + foreach ($this->class['tags'] as $item) { + if ($item['object'] instanceof $class) { $list[] = $this->instanciateAnnotationObject($item); } } - foreach($this->properties as $property) { - foreach($property['tags'] as $item) { - if ( $item['tag'] === $name ) { + foreach ($this->properties as $property) { + foreach ($property['tags'] as $item) { + if ($item['object'] instanceof $class) { $list[$property['name']] ??= []; $list[$property['name']][] = $this->instanciateAnnotationObject($item); @@ -88,17 +89,101 @@ class ObjectResolver { } } - foreach($this->methods as $method) { - foreach($method['tags'] as $item) { - if ( $item['tag'] === $name ) { + foreach ($this->methods as $method) { + foreach ($method['tags'] as $item) { + if ($item['object'] instanceof $class) { $list[$method['name']] ??= []; - $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)"); } @@ -107,6 +192,10 @@ class ObjectResolver { public function instanciateAnnotationObject(array $tagDefinition) : Annotation { + if (isset($tagDefinition['object']) && $tagDefinition['object'] instanceof \Attribute) { + return $tagDefinition['object']; + } + $arguments = $this->extractArguments($tagDefinition['arguments']); if ( false === $class = array_search($tagDefinition['tag'], $this->uses) ) { @@ -145,18 +234,18 @@ class ObjectResolver { protected function resolveAnnotations() { foreach($this->class['tags'] as $key => &$tag) { - $tag['object'] = $this->instanciateAnnotationObject($tag); + $tag['object'] ??= $this->instanciateAnnotationObject($tag); } foreach($this->properties as &$property) { foreach($property['tags'] as &$tag){ - $tag['object'] = $this->instanciateAnnotationObject($tag); + $tag['object'] ??= $this->instanciateAnnotationObject($tag); } } foreach($this->methods as &$method) { foreach($method['tags'] as &$tag){ - $tag['object'] = $this->instanciateAnnotationObject($tag); + $tag['object'] ??= $this->instanciateAnnotationObject($tag); } } }