From 2cbd75745a44457f5562861bb8993f028e3c8608 Mon Sep 17 00:00:00 2001 From: "nicolas.enrici" Date: Thu, 18 Jan 2024 16:51:06 +0100 Subject: [PATCH 1/6] feat(chore): Upgrade to PHP 8.2. --- composer.json | 7 ++++--- .../Helper/Traits/MethodOverloadAwareTrait.php | 2 +- src/PhpGenerator/Helper/VarPrinter.php | 6 +++--- src/PhpGenerator/Model/Constant.php | 4 ++-- src/PhpGenerator/Model/Method.php | 2 +- src/PhpGenerator/Model/QualifiedName.php | 2 +- src/PhpGenerator/Model/Struct.php | 7 ++----- src/PhpGenerator/Model/Type.php | 12 ++++++------ src/PhpGenerator/Model/Value.php | 13 ++----------- tests/PhpGenerator/Assert.php | 9 +++------ tests/PhpGenerator/Helper/StubHelper.php | 2 +- tests/PhpGenerator/Stub/Class2.php | 8 ++++---- tests/PhpGenerator/Stub/Class4.php | 2 +- tests/PhpGenerator/Stub/Class5.php | 2 +- tests/PhpGenerator/Stub/Class6.php | 2 +- tests/PhpGenerator/Stub/Class7.php | 2 +- 16 files changed, 34 insertions(+), 48 deletions(-) diff --git a/composer.json b/composer.json index 42d0366..1bedf72 100644 --- a/composer.json +++ b/composer.json @@ -13,15 +13,16 @@ } ], "require": { - "php": ">=7.4", - "roave/better-reflection": "^4.0@dev", + "php": ">=8.0", + "roave/better-reflection": "^6.22.0", "phpdocumentor/type-resolver": "^1.0@dev" }, "require-dev": { "php-coveralls/php-coveralls": "^2.4", - "phpstan/phpstan": "^0.12.0@dev", + "phpstan/phpstan": "^1.10.56", "phpunit/phpcov": "^8.2", "phpunit/phpunit": "^9.2@dev", + "rector/rector": "^0.19.1", "roave/security-advisories": "dev-master", "symfony/var-dumper": "^5.2@dev", "symplify/changelog-linker": "^8.3", diff --git a/src/PhpGenerator/Helper/Traits/MethodOverloadAwareTrait.php b/src/PhpGenerator/Helper/Traits/MethodOverloadAwareTrait.php index c825f45..1e72cac 100644 --- a/src/PhpGenerator/Helper/Traits/MethodOverloadAwareTrait.php +++ b/src/PhpGenerator/Helper/Traits/MethodOverloadAwareTrait.php @@ -38,7 +38,7 @@ protected static function buildMethodNameWithArgsTypes(string $baseName, array $ ); } $types[$i][] = $type; - $types[$i] = array_map([PhpHelper::class, 'extractShortName'], $types[$i]); + $types[$i] = array_map(PhpHelper::extractShortName(...), $types[$i]); } $argsNumber = \count($args); diff --git a/src/PhpGenerator/Helper/VarPrinter.php b/src/PhpGenerator/Helper/VarPrinter.php index a2610a5..909ac71 100644 --- a/src/PhpGenerator/Helper/VarPrinter.php +++ b/src/PhpGenerator/Helper/VarPrinter.php @@ -113,7 +113,7 @@ private static function dumpArray(array &$var, array $parents, int $level, int $ unset($v); array_pop($parents); - $wrap = false !== strpos($outInline, "\n") || $level * self::INDENT_LENGTH + $column + \strlen($outInline) + 3 > self::$wrapLength; + $wrap = str_contains($outInline, "\n") || $level * self::INDENT_LENGTH + $column + \strlen($outInline) + 3 > self::$wrapLength; return '[' . ($wrap ? $outWrapped : $outInline) . ']'; } @@ -128,7 +128,7 @@ private static function dumpObject($var, array $parents, int $level): string throw new \InvalidArgumentException('Cannot dump closure.'); } - $class = \get_class($var); + $class = $var::class; if ((new ReflectionObject($var))->isAnonymous()) { throw new \InvalidArgumentException('Cannot dump anonymous class.'); } @@ -170,6 +170,6 @@ private static function dumpObject($var, array $parents, int $level): string return \stdClass::class === $class ? "(object) [$out]" - : __CLASS__ . "::createObject('$class', [$out])"; + : self::class . "::createObject('$class', [$out])"; } } diff --git a/src/PhpGenerator/Model/Constant.php b/src/PhpGenerator/Model/Constant.php index 6726b2a..41b5a8e 100644 --- a/src/PhpGenerator/Model/Constant.php +++ b/src/PhpGenerator/Model/Constant.php @@ -7,14 +7,14 @@ use Sidux\PhpGenerator\Model\Contract\Member; use Sidux\PhpGenerator\Model\Contract\ValueAware; -class Constant extends Member implements ValueAware +class Constant extends Member implements ValueAware, \Stringable { use Part\NamespaceAwareTrait; use Part\VisibilityAwareTrait; use Part\CommentAwareTrait; use Part\ValueAwareTrait; - public const DEFAULT_VISIBILITY = Struct::PUBLIC; + final public const DEFAULT_VISIBILITY = Struct::PUBLIC; public static function create(string $name): self { diff --git a/src/PhpGenerator/Model/Method.php b/src/PhpGenerator/Model/Method.php index fcd7ab4..a36a850 100644 --- a/src/PhpGenerator/Model/Method.php +++ b/src/PhpGenerator/Model/Method.php @@ -71,7 +71,7 @@ public static function fromArray(array $from): self { [$className, $methodName] = $from; if (\is_object($className)) { - $className = \get_class($className); + $className = $className::class; } $ref = ReflectionMethod::createFromName($className, $methodName); diff --git a/src/PhpGenerator/Model/QualifiedName.php b/src/PhpGenerator/Model/QualifiedName.php index ac41e9f..42e4c11 100644 --- a/src/PhpGenerator/Model/QualifiedName.php +++ b/src/PhpGenerator/Model/QualifiedName.php @@ -7,7 +7,7 @@ use Sidux\PhpGenerator\Model\Contract\Member; use Sidux\PhpGenerator\Model\Contract\NamespaceAware; -class QualifiedName extends Member implements NamespaceAware +class QualifiedName extends Member implements NamespaceAware, \Stringable { use Part\NamespaceAwareTrait; diff --git a/src/PhpGenerator/Model/Struct.php b/src/PhpGenerator/Model/Struct.php index fc70844..fd30283 100644 --- a/src/PhpGenerator/Model/Struct.php +++ b/src/PhpGenerator/Model/Struct.php @@ -110,9 +110,7 @@ final class Struct implements NamespaceAware, Element public function __clone() { - $clone = static function ($item) { - return clone $item; - }; + $clone = static fn($item) => clone $item; $this->namespaceUses = array_map($clone, $this->namespaceUses); $this->traits = array_map($clone, $this->traits); @@ -556,9 +554,8 @@ public function setStrictTypes(bool $strictTypes): void /** * @param Constant|string $const - * @param mixed $value */ - public function addConstant($const, $value = null): Constant + public function addConstant($const, mixed $value = null): Constant { if (!$const instanceof Constant) { $const = new Constant($const); diff --git a/src/PhpGenerator/Model/Type.php b/src/PhpGenerator/Model/Type.php index 50be4a0..e5c55fc 100644 --- a/src/PhpGenerator/Model/Type.php +++ b/src/PhpGenerator/Model/Type.php @@ -16,7 +16,7 @@ class Type implements Element, NamespaceAware use Part\NamespaceAwareTrait; use Helper\Traits\MethodOverloadAwareTrait; - public const INTERNAL_TYPES = [ + final public const INTERNAL_TYPES = [ 'string', 'bool', 'int', @@ -31,7 +31,7 @@ class Type implements Element, NamespaceAware 'null', ]; - public const + final public const STRING = 'string', INT = 'int', FLOAT = 'float', @@ -63,14 +63,14 @@ public function __construct($type) } $type = (string)$type; - if (0 === strncmp($type, '?', 1)) { + if (str_starts_with($type, '?')) { $this->nullable = true; $type = str_replace('?', '', $type); } if (!PhpHelper::isNamespaceIdentifier($type)) { throw new \InvalidArgumentException("Value '$type' is not a valid type."); } - if ('[]' === substr($type, -2, 2)) { + if (str_ends_with($type, '[]')) { $this->collection = true; $type = str_replace('[]', '', $type); } @@ -98,7 +98,7 @@ public static function create(...$args): self public static function fromReflectionType(ReflectionType $ref): self { $name = (string)$ref; - if (!$ref->isBuiltin() && false === strpos($name, '\\')) { + if (!$ref->isBuiltin() && !str_contains($name, '\\')) { $name = '\\' . $name; } $type = self::create($name); @@ -116,7 +116,7 @@ public static function fromString(string $qualifiedName): self public static function getType($value): ?string { if (\is_object($value)) { - return \get_class($value); + return $value::class; } if (\is_int($value)) { diff --git a/src/PhpGenerator/Model/Value.php b/src/PhpGenerator/Model/Value.php index db32cef..ace3394 100644 --- a/src/PhpGenerator/Model/Value.php +++ b/src/PhpGenerator/Model/Value.php @@ -7,21 +7,12 @@ use Sidux\PhpGenerator\Helper\VarPrinter; use Sidux\PhpGenerator\Model\Contract\ValueAware; -class Value +class Value implements \Stringable { - private $value; - - private bool $literal; - private ?ValueAware $parent = null; - /** - * @param mixed $value - */ - public function __construct($value, bool $literal = true) + public function __construct(private readonly mixed $value, private readonly bool $literal = true) { - $this->value = $value; - $this->literal = $literal; } public function __toString(): string diff --git a/tests/PhpGenerator/Assert.php b/tests/PhpGenerator/Assert.php index d21e46c..e3f1445 100644 --- a/tests/PhpGenerator/Assert.php +++ b/tests/PhpGenerator/Assert.php @@ -58,7 +58,7 @@ private static function fixThrowableClass(?string $throwableClass, string $defau try { $reflection = new \ReflectionClass($throwableClass); $throwableClass = $reflection->getName(); - } catch (\ReflectionException $e) { + } catch (\ReflectionException) { static::fail( sprintf( '%s of type "%s" does not exist.', @@ -117,7 +117,6 @@ private static function resolveThrowableCaption(string $throwableClass): string } /** - * @param \Throwable $throwable * @param int|string|null $expectedCode */ private static function checkThrowableCode(\Throwable $throwable, $expectedCode): void @@ -126,7 +125,7 @@ private static function checkThrowableCode(\Throwable $throwable, $expectedCode) static::assertEquals( $expectedCode, $throwable->getCode(), - sprintf('Failed asserting the code of thrown %s.', \get_class($throwable)) + sprintf('Failed asserting the code of thrown %s.', $throwable::class) ); } } @@ -137,14 +136,12 @@ private static function checkThrowableMessage(\Throwable $throwable, string $exp static::assertStringContainsString( $throwable->getMessage(), $expectedMessage, - sprintf('Failed asserting the message of thrown %s.', \get_class($throwable)) + sprintf('Failed asserting the message of thrown %s.', $throwable::class) ); } } /** - * @param string $expectedThrowableClass - * * @throws AssertionFailedError */ private static function failAssertingThrowable(string $expectedThrowableClass): void diff --git a/tests/PhpGenerator/Helper/StubHelper.php b/tests/PhpGenerator/Helper/StubHelper.php index 7a77ab4..a25e294 100644 --- a/tests/PhpGenerator/Helper/StubHelper.php +++ b/tests/PhpGenerator/Helper/StubHelper.php @@ -13,7 +13,7 @@ public static function load(string $name, $require = true): string throw new \RuntimeException("file $filePath does not exist or is not readable"); } $content = file_get_contents($filePath); - if ($require && strpos($content, ' Date: Thu, 1 Feb 2024 16:43:03 +0100 Subject: [PATCH 2/6] feat(php8): Added promoted parameters logic --- composer.json | 2 +- src/PhpGenerator/Model/Method.php | 27 +++++++++- src/PhpGenerator/Model/Parameter.php | 7 ++- .../Model/Part/ReadOnlyAwareTrait.php | 20 ++++++++ .../Model/Part/TypeAwareTrait.php | 5 ++ src/PhpGenerator/Model/PromotedParameter.php | 49 +++++++++++++++++++ src/PhpGenerator/Model/Struct.php | 2 + .../Expected/ClassType.from.82.expect | 18 +++++++ tests/PhpGenerator/Model/StructTest.php | 25 ++++++++++ 9 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 src/PhpGenerator/Model/Part/ReadOnlyAwareTrait.php create mode 100644 src/PhpGenerator/Model/PromotedParameter.php create mode 100644 tests/PhpGenerator/Expected/ClassType.from.82.expect diff --git a/composer.json b/composer.json index 1bedf72..744ff52 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ } ], "require": { - "php": ">=8.0", + "php": ">=8.2", "roave/better-reflection": "^6.22.0", "phpdocumentor/type-resolver": "^1.0@dev" }, diff --git a/src/PhpGenerator/Model/Method.php b/src/PhpGenerator/Model/Method.php index a36a850..de0a753 100644 --- a/src/PhpGenerator/Model/Method.php +++ b/src/PhpGenerator/Model/Method.php @@ -52,10 +52,17 @@ public function __toString(): string $output .= $this->isReference() ? '&' : null; $output .= $this->getName(); $output .= '('; - $output .= implode(', ', $this->getParameters()); + + if (\count($this->getParameters()) >= 2) { + $output .= "\n"; + $output .= StringHelper::indent(implode(",\n", $this->getParameters())); + $output .= "\n"; + } else { + $output .= implode(', ', $this->getParameters()); + } $output .= ')'; $output .= $this->getTypeHint() ? ': ' . $this->getTypeHint() : null; - $output .= $this->hasBody() ? "\n{\n" : ";\n"; + $output .= $this->hasBody() ? $this->isBodyEmpty() ? " {\n" : "\n{\n" : ";\n"; $output .= $this->hasBody() && $this->getBody() ? StringHelper::indent($this->getBody()) . "\n" : null; $output .= $this->hasBody() ? "}\n" : null; @@ -254,6 +261,17 @@ public function addParameter($parameter): Parameter return $parameter; } + public function addPromotedParameter(string|PromotedParameter $promotedParameter, string $visibility = Struct::PUBLIC): self + { + if (!$promotedParameter instanceof PromotedParameter) { + $promotedParameter = new PromotedParameter($promotedParameter, $visibility); + } + $promotedParameter->setParent($this); + $this->parameters[$promotedParameter->getName()] = $promotedParameter; + + return $this; + } + /** * @psalm-return value-of */ @@ -316,4 +334,9 @@ public function resolve(): self return $this; } + + public function isBodyEmpty(): bool + { + return isset($this->body); + } } diff --git a/src/PhpGenerator/Model/Parameter.php b/src/PhpGenerator/Model/Parameter.php index f1f7008..3564e71 100644 --- a/src/PhpGenerator/Model/Parameter.php +++ b/src/PhpGenerator/Model/Parameter.php @@ -13,7 +13,7 @@ /** * @method static self from(ReflectionParameter|string|array $from) */ -final class Parameter implements ValueAware, Element, TypeAware +class Parameter implements ValueAware, Element, TypeAware { use Part\NameAwareTrait; use Part\ValueAwareTrait; @@ -46,6 +46,11 @@ public static function create(string $name): self public function __toString(): string { $output = ''; + + if ($this instanceof PromotedParameter) { + $output .= $this->getVisibility() . ' '; + } + $output .= (string)$this->getTypeHint() ? $this->getTypeHint() . ' ' : null; $output .= $this->isReference() ? '&' : null; $output .= $this->isVariadic() ? '...' : null; diff --git a/src/PhpGenerator/Model/Part/ReadOnlyAwareTrait.php b/src/PhpGenerator/Model/Part/ReadOnlyAwareTrait.php new file mode 100644 index 0000000..86d74d9 --- /dev/null +++ b/src/PhpGenerator/Model/Part/ReadOnlyAwareTrait.php @@ -0,0 +1,20 @@ +readOnly; + } + + public function setReadOnly(bool $readOnly): void + { + $this->readOnly = $readOnly; + } +} diff --git a/src/PhpGenerator/Model/Part/TypeAwareTrait.php b/src/PhpGenerator/Model/Part/TypeAwareTrait.php index a744fe6..e69a27b 100644 --- a/src/PhpGenerator/Model/Part/TypeAwareTrait.php +++ b/src/PhpGenerator/Model/Part/TypeAwareTrait.php @@ -40,6 +40,11 @@ public function getDocTypes(): array public function getTypeHint(): ?string { $types = $this->getTypes(); + if (\count($types) > 2) { + //Add a check to validate types + return implode('|', $types); + } + $prefix = $this->isNullable() ? '?' : ''; if (isset($types[Type::NULL])) { unset($types[Type::NULL]); diff --git a/src/PhpGenerator/Model/PromotedParameter.php b/src/PhpGenerator/Model/PromotedParameter.php new file mode 100644 index 0000000..d167858 --- /dev/null +++ b/src/PhpGenerator/Model/PromotedParameter.php @@ -0,0 +1,49 @@ +visibility = $visibility; + parent::__construct($name); + } + + public static function create(string $name, string $visibility = Struct::PUBLIC): PromotedParameter + { + return new self($name, $visibility); + } + + public function getVisibility(): string + { + return $this->visibility; + } + + public function setReadOnly(bool $state = true): PromotedParameter + { + $this->readOnly = $state; + return $this; + } + + public function isReadOnly(): bool + { + return $this->readOnly; + } + + /** + * @throws \Exception + */ + public function validate(): void + { + if ($this->readOnly && count($this->getTypes()) === 0) { + throw new \Exception("Property \${$this->getName()}: Read-only properties are only supported on typed property."); + } + } +} diff --git a/src/PhpGenerator/Model/Struct.php b/src/PhpGenerator/Model/Struct.php index fd30283..ba21350 100644 --- a/src/PhpGenerator/Model/Struct.php +++ b/src/PhpGenerator/Model/Struct.php @@ -25,6 +25,7 @@ final class Struct implements NamespaceAware, Element use Part\NamespaceAwareTrait; use Part\FinalAwareTrait; use Part\AbstractAwareTrait; + use Part\ReadOnlyAwareTrait; use Helper\Traits\MethodOverloadAwareTrait; public const TYPES = [ @@ -131,6 +132,7 @@ public function __toString(): string $output .= $this->commentsToString(); $output .= $this->isAbstract() ? 'abstract ' : null; $output .= $this->isFinal() ? 'final ' : null; + $output .= $this->isReadOnly() ? 'readonly ' : null; $output .= $this->type . ' '; $output .= $this->getName(); $output .= $this->getExtends() ? ' extends ' . implode(', ', $this->getExtends()) : null; diff --git a/tests/PhpGenerator/Expected/ClassType.from.82.expect b/tests/PhpGenerator/Expected/ClassType.from.82.expect new file mode 100644 index 0000000..d512304 --- /dev/null +++ b/tests/PhpGenerator/Expected/ClassType.from.82.expect @@ -0,0 +1,18 @@ +setReadOnly(true); + $class->addNamespaceUse('Sidux\PhpGenerator\Stub\PropertyTwo'); + + $objectClass = new Struct('Sidux\PhpGenerator\Stub\PropertyTwo'); + $constructor = $class->addConstructor(); + + $constructor + ->addPromotedParameter(PromotedParameter::create('propertyOne')->addType('string')) + ->addPromotedParameter(PromotedParameter::create('propertyTwo')->addType($objectClass)) + ->addPromotedParameter(PromotedParameter::create('propertyThree')->addTypes(['string', 'array', 'null'])) + ->addPromotedParameter(PromotedParameter::create('propertyFour')->addTypes(['string', 'null'])->setValue(null)) + + ; + + + Assert::assertExpect('ClassType.from.82.expect', $class); + } } From a7562f92d5c0bef24c7902f1764bcfa49fc115a5 Mon Sep 17 00:00:00 2001 From: Christelle Canovas Date: Thu, 1 Feb 2024 18:18:56 +0100 Subject: [PATCH 3/6] feat(php8): Added Enum logic --- src/PhpGenerator/Model/EnumCase.php | 27 ++++++++ src/PhpGenerator/Model/Struct.php | 66 ++++++++++++++++++- src/PhpGenerator/Model/Type.php | 5 ++ .../Expected/EnumType.from.82.expect | 13 ++++ tests/PhpGenerator/Model/StructTest.php | 14 +++- 5 files changed, 122 insertions(+), 3 deletions(-) create mode 100644 src/PhpGenerator/Model/EnumCase.php create mode 100644 tests/PhpGenerator/Expected/EnumType.from.82.expect diff --git a/src/PhpGenerator/Model/EnumCase.php b/src/PhpGenerator/Model/EnumCase.php new file mode 100644 index 0000000..8e6c756 --- /dev/null +++ b/src/PhpGenerator/Model/EnumCase.php @@ -0,0 +1,27 @@ +getName()} = {$this->getValue()};"; + + return $output; + } +} diff --git a/src/PhpGenerator/Model/Struct.php b/src/PhpGenerator/Model/Struct.php index ba21350..5bf2515 100644 --- a/src/PhpGenerator/Model/Struct.php +++ b/src/PhpGenerator/Model/Struct.php @@ -32,12 +32,14 @@ final class Struct implements NamespaceAware, Element Struct::_CLASS, Struct::_INTERFACE, Struct::_TRAIT, + Struct::_ENUM ]; public const _CLASS = 'class', _INTERFACE = 'interface', - _TRAIT = 'trait'; + _TRAIT = 'trait', + _ENUM = 'enum'; public const VISIBILITIES = [ Struct::PUBLIC, @@ -109,6 +111,16 @@ final class Struct implements NamespaceAware, Element */ private string $defaultMethodVisibility = Method::DEFAULT_VISIBILITY; + /** + * @psalm-var value-of + */ + private ?string $enumType = null; + + /** + * @var array + */ + private array $cases = []; + public function __clone() { $clone = static fn($item) => clone $item; @@ -135,6 +147,7 @@ public function __toString(): string $output .= $this->isReadOnly() ? 'readonly ' : null; $output .= $this->type . ' '; $output .= $this->getName(); + $output .= $this->isBackedEnum() ? ": $this->enumType" : null; $output .= $this->getExtends() ? ' extends ' . implode(', ', $this->getExtends()) : null; $output .= $this->getImplements() ? ' implements ' . implode(', ', $this->getImplements()) : null; $output .= "\n{\n"; @@ -145,8 +158,15 @@ public function __toString(): string implode("\n", $this->getConstants()), implode("\n", $this->getProperties()), implode("\n", $this->getMethods()), + implode("\n", $this->getCases()), ] ); + + if (\count($this->getCases()) > 0) { + $lastCase = array_pop($members); + $members[] = $lastCase . "\n"; + } + $output .= $members ? StringHelper::indent(implode("\n", $members)) : null; $output .= "}\n"; @@ -784,4 +804,48 @@ private function validateName(string $name): void throw new \InvalidArgumentException("Value '$name' is not valid class name."); } } + + public function isBackedEnum(): bool + { + return isset($this->enumType); + } + + public function getCases(): array + { + return $this->cases; + } + + /** + * @psalm-param value-of $type + */ + public function setEnumType(string $type): void + { + if (!in_array($type, Type::BACKED_ENUM, true)) { + throw new \InvalidArgumentException("Invalid backed enum type '$type'."); + } + + $this->enumType = $type; + } + + public function setCases(array $cases): void + { + $firstCase = reset($cases); + $enumType = gettype($firstCase); + + $enumCases = []; + + foreach ($cases as $name => $value) { + if (gettype($value) !== $enumType) { + throw new \InvalidArgumentException("All cases of the enum must be of the same type."); + } + + $enumCase = EnumCase::create($name); + $enumCase->setValue($value); + + $enumCases[] = $enumCase; + } + + $this->setEnumType($enumType); + $this->cases = $enumCases; + } } diff --git a/src/PhpGenerator/Model/Type.php b/src/PhpGenerator/Model/Type.php index e5c55fc..054af8e 100644 --- a/src/PhpGenerator/Model/Type.php +++ b/src/PhpGenerator/Model/Type.php @@ -45,6 +45,11 @@ class Type implements Element, NamespaceAware SELF = 'self', PARENT = 'parent'; + final public const BACKED_ENUM = [ + 'string', + 'int', + ]; + private bool $internal = false; private bool $collection = false; diff --git a/tests/PhpGenerator/Expected/EnumType.from.82.expect b/tests/PhpGenerator/Expected/EnumType.from.82.expect new file mode 100644 index 0000000..f65da29 --- /dev/null +++ b/tests/PhpGenerator/Expected/EnumType.from.82.expect @@ -0,0 +1,13 @@ +addPromotedParameter(PromotedParameter::create('propertyTwo')->addType($objectClass)) ->addPromotedParameter(PromotedParameter::create('propertyThree')->addTypes(['string', 'array', 'null'])) ->addPromotedParameter(PromotedParameter::create('propertyFour')->addTypes(['string', 'null'])->setValue(null)) - ; - Assert::assertExpect('ClassType.from.82.expect', $class); } + + /** + * @test + */ + public function generatePhp82EnumClass(): void + { + $class = new Struct('Sidux\PhpGenerator\Stub\Gender'); + $class->setType('enum'); + $class->setCases(['M' => 'M', 'F' => 'F', 'N' => 'N', 'U' => 'U']); + + Assert::assertExpect('EnumType.from.82.expect', $class); + } } From ddea7eade299077ef706c7dee1c577f4dfec8886 Mon Sep 17 00:00:00 2001 From: Christelle Canovas Date: Tue, 6 Feb 2024 12:08:23 +0100 Subject: [PATCH 4/6] chore(parameter): Simplified promoted parameter logic --- src/PhpGenerator/Model/Method.php | 49 +++++++++---------- src/PhpGenerator/Model/Parameter.php | 40 +++++++++++++-- .../Model/Part/CommentAwareTrait.php | 2 +- .../Model/Part/TypeAwareTrait.php | 5 +- src/PhpGenerator/Model/PromotedParameter.php | 49 ------------------- .../Expected/ClassType.from.82.expect | 5 +- tests/PhpGenerator/Helper/VarPrinterTest.php | 2 +- tests/PhpGenerator/Model/StructTest.php | 29 +++++++---- .../Stub/SubNamespace/PropertyTwo.php | 10 ++++ 9 files changed, 96 insertions(+), 95 deletions(-) delete mode 100644 src/PhpGenerator/Model/PromotedParameter.php create mode 100644 tests/PhpGenerator/Stub/SubNamespace/PropertyTwo.php diff --git a/src/PhpGenerator/Model/Method.php b/src/PhpGenerator/Model/Method.php index de0a753..61d9a7b 100644 --- a/src/PhpGenerator/Model/Method.php +++ b/src/PhpGenerator/Model/Method.php @@ -29,6 +29,8 @@ final class Method extends Member implements Element, TypeAware public const DEFAULT_VISIBILITY = Struct::PUBLIC; + public const CONSTRUCTOR = '__construct'; + private ?string $body = ''; /** @@ -38,6 +40,11 @@ final class Method extends Member implements Element, TypeAware private bool $variadic = false; + /** + * @psalm-var value-of + */ + private string $defaultParameterVisibility = Parameter::DEFAULT_VISIBILITY; + public function __toString(): string { $this->validate(); @@ -52,23 +59,23 @@ public function __toString(): string $output .= $this->isReference() ? '&' : null; $output .= $this->getName(); $output .= '('; - - if (\count($this->getParameters()) >= 2) { - $output .= "\n"; - $output .= StringHelper::indent(implode(",\n", $this->getParameters())); - $output .= "\n"; - } else { - $output .= implode(', ', $this->getParameters()); - } + $output .= $this->hasMoreThanTwoParameters() ? "\n" : null; + $output .= $this->hasMoreThanTwoParameters() ? StringHelper::indent(implode(",\n", $this->getParameters())) : implode(', ', $this->getParameters()); + $output .= $this->hasMoreThanTwoParameters() ? "\n" : null; $output .= ')'; $output .= $this->getTypeHint() ? ': ' . $this->getTypeHint() : null; - $output .= $this->hasBody() ? $this->isBodyEmpty() ? " {\n" : "\n{\n" : ";\n"; + $output .= $this->hasBody() ? "\n{\n" : ";\n"; $output .= $this->hasBody() && $this->getBody() ? StringHelper::indent($this->getBody()) . "\n" : null; $output .= $this->hasBody() ? "}\n" : null; return $output; } + private function hasMoreThanTwoParameters(): bool + { + return \count($this->getParameters()) > 2; + } + public static function create(string $name): self { return new self($name); @@ -261,17 +268,6 @@ public function addParameter($parameter): Parameter return $parameter; } - public function addPromotedParameter(string|PromotedParameter $promotedParameter, string $visibility = Struct::PUBLIC): self - { - if (!$promotedParameter instanceof PromotedParameter) { - $promotedParameter = new PromotedParameter($promotedParameter, $visibility); - } - $promotedParameter->setParent($this); - $this->parameters[$promotedParameter->getName()] = $promotedParameter; - - return $this; - } - /** * @psalm-return value-of */ @@ -285,6 +281,14 @@ public function getDefaultVisibility(): string return self::DEFAULT_VISIBILITY; } + /** + * @psalm-return value-of + */ + public function getDefaultParameterVisibility(): string + { + return $this->defaultParameterVisibility; + } + /** * @param string|Property $initProperty */ @@ -334,9 +338,4 @@ public function resolve(): self return $this; } - - public function isBodyEmpty(): bool - { - return isset($this->body); - } } diff --git a/src/PhpGenerator/Model/Parameter.php b/src/PhpGenerator/Model/Parameter.php index 3564e71..0b03e17 100644 --- a/src/PhpGenerator/Model/Parameter.php +++ b/src/PhpGenerator/Model/Parameter.php @@ -9,6 +9,7 @@ use Sidux\PhpGenerator\Model\Contract\Element; use Sidux\PhpGenerator\Model\Contract\TypeAware; use Sidux\PhpGenerator\Model\Contract\ValueAware; +use Sidux\PhpGenerator\Model\Part\ReadOnlyAwareTrait; /** * @method static self from(ReflectionParameter|string|array $from) @@ -19,10 +20,16 @@ class Parameter implements ValueAware, Element, TypeAware use Part\ValueAwareTrait; use Part\TypeAwareTrait; use Part\ReferenceAwareTrait; + use Part\VisibilityAwareTrait; use Helper\Traits\MethodOverloadAwareTrait; + use ReadOnlyAwareTrait; + + final public const DEFAULT_VISIBILITY = Struct::PRIVATE; private ?Method $parent = null; + private bool $isPromoted = false; + public function __construct(string $name) { $this->setName($name); @@ -46,11 +53,8 @@ public static function create(string $name): self public function __toString(): string { $output = ''; - - if ($this instanceof PromotedParameter) { - $output .= $this->getVisibility() . ' '; - } - + $output .= $this->isPromoted() ? $this->getVisibility() . ' ' : null; + $output .= $this->isReadOnly() ? 'readonly ' : null; $output .= (string)$this->getTypeHint() ? $this->getTypeHint() . ' ' : null; $output .= $this->isReference() ? '&' : null; $output .= $this->isVariadic() ? '...' : null; @@ -111,4 +115,30 @@ public function resolve(): self return $this; } + + public function getDefaultVisibility(): string + { + $parent = $this->getParent(); + if ($parent) { + return $parent->getDefaultParameterVisibility(); + } + + return self::DEFAULT_VISIBILITY; + } + + public function setPromoted(): self + { + if ($this->getParent() && $this->getParent()->getName() !== Method::CONSTRUCTOR) { + throw new \RuntimeException('Promotion is only allowed for constructor parameters'); + } + + $this->isPromoted = true; + + return $this; + } + + public function isPromoted(): bool + { + return $this->isPromoted; + } } diff --git a/src/PhpGenerator/Model/Part/CommentAwareTrait.php b/src/PhpGenerator/Model/Part/CommentAwareTrait.php index 921d1a8..2b097ef 100644 --- a/src/PhpGenerator/Model/Part/CommentAwareTrait.php +++ b/src/PhpGenerator/Model/Part/CommentAwareTrait.php @@ -27,7 +27,7 @@ public function getComments(): array return $this->comments; } - public function setComment(string $value): self + public function setComment(?string $value): self { if (!$value) { return $this; diff --git a/src/PhpGenerator/Model/Part/TypeAwareTrait.php b/src/PhpGenerator/Model/Part/TypeAwareTrait.php index e69a27b..fd7040f 100644 --- a/src/PhpGenerator/Model/Part/TypeAwareTrait.php +++ b/src/PhpGenerator/Model/Part/TypeAwareTrait.php @@ -41,7 +41,6 @@ public function getTypeHint(): ?string { $types = $this->getTypes(); if (\count($types) > 2) { - //Add a check to validate types return implode('|', $types); } @@ -101,9 +100,9 @@ public function isNullable(): bool return false; } - public function addTypeFromNamespaceAware(NamespaceAware $stuct): self + public function addTypeFromNamespaceAware(NamespaceAware $struct): self { - $type = $stuct->getQualifiedName(); + $type = $struct->getQualifiedName(); return $this->addTypeFromString($type); } diff --git a/src/PhpGenerator/Model/PromotedParameter.php b/src/PhpGenerator/Model/PromotedParameter.php deleted file mode 100644 index d167858..0000000 --- a/src/PhpGenerator/Model/PromotedParameter.php +++ /dev/null @@ -1,49 +0,0 @@ -visibility = $visibility; - parent::__construct($name); - } - - public static function create(string $name, string $visibility = Struct::PUBLIC): PromotedParameter - { - return new self($name, $visibility); - } - - public function getVisibility(): string - { - return $this->visibility; - } - - public function setReadOnly(bool $state = true): PromotedParameter - { - $this->readOnly = $state; - return $this; - } - - public function isReadOnly(): bool - { - return $this->readOnly; - } - - /** - * @throws \Exception - */ - public function validate(): void - { - if ($this->readOnly && count($this->getTypes()) === 0) { - throw new \Exception("Property \${$this->getName()}: Read-only properties are only supported on typed property."); - } - } -} diff --git a/tests/PhpGenerator/Expected/ClassType.from.82.expect b/tests/PhpGenerator/Expected/ClassType.from.82.expect index d512304..c7cfb0f 100644 --- a/tests/PhpGenerator/Expected/ClassType.from.82.expect +++ b/tests/PhpGenerator/Expected/ClassType.from.82.expect @@ -4,7 +4,7 @@ declare(strict_types=1); namespace Sidux\PhpGenerator\Stub; -use Sidux\PhpGenerator\Stub\PropertyTwo; +use PhpGenerator\Stub\SubNamespace\PropertyTwo; readonly class RequestClass { @@ -13,6 +13,7 @@ readonly class RequestClass public PropertyTwo $propertyTwo, public string|array|null $propertyThree, public ?string $propertyFour = null - ) { + ) + { } } diff --git a/tests/PhpGenerator/Helper/VarPrinterTest.php b/tests/PhpGenerator/Helper/VarPrinterTest.php index e23ec4b..03ba4e9 100644 --- a/tests/PhpGenerator/Helper/VarPrinterTest.php +++ b/tests/PhpGenerator/Helper/VarPrinterTest.php @@ -128,7 +128,7 @@ public function all(): void Assert::assertSame( - VarPrinter::class . "::createObject('Sidux\\PhpGenerator\\Stub\\Test2', [\n \"\\x00Sidux\\\PhpGenerator\\\Stub\\\Test2\\x00c\" => 4,\n 'a' => 1,\n \"\\x00*\\x00b\" => 2,\n])", + VarPrinter::class . "::createObject('Sidux\\PhpGenerator\\Stub\\Test2', [\n 'a' => 1,\n \"\\x00*\\x00b\" => 2,\n \"\\x00Sidux\\\PhpGenerator\\\Stub\\\Test2\\x00c\" => 4,\n])", VarPrinter::dump(new Test2()) ); /** @noinspection PhpUnreachableStatementInspection */ diff --git a/tests/PhpGenerator/Model/StructTest.php b/tests/PhpGenerator/Model/StructTest.php index e5d27fa..63b37fa 100644 --- a/tests/PhpGenerator/Model/StructTest.php +++ b/tests/PhpGenerator/Model/StructTest.php @@ -5,7 +5,6 @@ namespace Sidux\PhpGenerator\Model; use PHPUnit\Framework\TestCase; -use ReflectionType; use Roave\BetterReflection\Reflection\ReflectionClass; use Roave\BetterReflection\Reflection\ReflectionObject; use Sidux\PhpGenerator\Assert; @@ -462,17 +461,29 @@ public function generate82Class(): void { $class = new Struct('Sidux\PhpGenerator\Stub\RequestClass'); $class->setReadOnly(true); - $class->addNamespaceUse('Sidux\PhpGenerator\Stub\PropertyTwo'); - $objectClass = new Struct('Sidux\PhpGenerator\Stub\PropertyTwo'); + $objectClass = new Struct('PhpGenerator\Stub\SubNamespace\PropertyTwo'); $constructor = $class->addConstructor(); - $constructor - ->addPromotedParameter(PromotedParameter::create('propertyOne')->addType('string')) - ->addPromotedParameter(PromotedParameter::create('propertyTwo')->addType($objectClass)) - ->addPromotedParameter(PromotedParameter::create('propertyThree')->addTypes(['string', 'array', 'null'])) - ->addPromotedParameter(PromotedParameter::create('propertyFour')->addTypes(['string', 'null'])->setValue(null)) - ; + $constructor->setParameters([ + Parameter::create('propertyOne') + ->addType('string') + ->setVisibility(Struct::PUBLIC) + ->setPromoted(), + Parameter::create('propertyTwo') + ->addType($objectClass) + ->setVisibility(Struct::PUBLIC) + ->setPromoted(), + Parameter::create('propertyThree') + ->addTypes(['string', 'array', 'null']) + ->setVisibility(Struct::PUBLIC) + ->setPromoted(), + Parameter::create('propertyFour') + ->addTypes(['string', 'null']) + ->setValue(null) + ->setVisibility(Struct::PUBLIC) + ->setPromoted(), + ]); Assert::assertExpect('ClassType.from.82.expect', $class); } diff --git a/tests/PhpGenerator/Stub/SubNamespace/PropertyTwo.php b/tests/PhpGenerator/Stub/SubNamespace/PropertyTwo.php new file mode 100644 index 0000000..1e0a01f --- /dev/null +++ b/tests/PhpGenerator/Stub/SubNamespace/PropertyTwo.php @@ -0,0 +1,10 @@ + Date: Sat, 10 Feb 2024 16:29:48 +0100 Subject: [PATCH 5/6] chore(roave): Removed Roave lib usages --- src/PhpGenerator/Helper/ReflectionHelper.php | 239 ++++++++++++++++++ .../Traits/MethodOverloadAwareTrait.php | 6 +- src/PhpGenerator/Model/Contract/TypeAware.php | 7 +- src/PhpGenerator/Model/Method.php | 56 ++-- src/PhpGenerator/Model/Parameter.php | 17 +- .../Model/Part/TypeAwareTrait.php | 14 +- src/PhpGenerator/Model/Property.php | 22 +- src/PhpGenerator/Model/Struct.php | 53 ++-- src/PhpGenerator/Model/Type.php | 16 +- .../Expected/ClassType.from.74.expect | 2 +- .../Expected/ClassType.from.expect | 2 +- tests/PhpGenerator/Model/MethodTest.php | 12 +- tests/PhpGenerator/Model/ParameterTest.php | 12 +- tests/PhpGenerator/Model/StructTest.php | 54 ++-- .../Stub/SubNamespace/PropertyTwo.php | 2 +- 15 files changed, 410 insertions(+), 104 deletions(-) create mode 100644 src/PhpGenerator/Helper/ReflectionHelper.php diff --git a/src/PhpGenerator/Helper/ReflectionHelper.php b/src/PhpGenerator/Helper/ReflectionHelper.php new file mode 100644 index 0000000..99fe6b9 --- /dev/null +++ b/src/PhpGenerator/Helper/ReflectionHelper.php @@ -0,0 +1,239 @@ +isAbstract())) { + return ''; + } + + $filename = $reflection->getFileName(); + + if ($filename === false) { + throw new \LogicException("Filename is not set"); + } + + $file = file($filename); + + if ($file === false) { + throw new \LogicException("Unable to open file {$filename}."); + } + + $startLine = self::getBodyCodeStartLine($reflection->getName(), $file); + $endLine = self::getBodyCodeEndLine($reflection->getName(), $file); + + $length = $endLine - $startLine + 1; + + if ($length <= 2) { + $length = 0; + } + + $code = \array_slice($file, $startLine, $length); + + return trim(preg_replace('/\s+{\n|\s+}\n/', '', implode('', $code))); + } + + public static function getBodyCodeStartLine(string $functionOrMethodName, array $file): int + { + $startLine = 0; + $found = false; + + foreach ($file as $lineNumber => $line) { + if (str_contains($line, $functionOrMethodName)) { + $startLine = $lineNumber; + $found = true; + } + + if ($found && str_contains($line, '{')) { + $startLine = $lineNumber; + break; + } + } + + return $startLine; + } + + public static function getBodyCodeEndLine(string $functionOrMethodName, array $file): int + { + $endLine = 0; + $found = false; + + foreach ($file as $lineNumber => $line) { + if (str_contains($line, $functionOrMethodName)) { + $endLine = $lineNumber; + $found = true; + } + + if ($found && str_contains($line, '}')) { + $endLine = $lineNumber; + break; + } + } + + return $endLine; + } + + public static function getDocBlockReturnTypes(ReflectionFunction|ReflectionMethod|\PHPStan\BetterReflection\Reflection\ReflectionFunction $reflection): array + { + $docBlockFactory = DocBlockFactory::createInstance(); + $typeResolver = new TypeResolver(); + $docComment = $reflection->getDocComment(); + $context = $reflection->getNamespaceName() ? new Context($reflection->getNamespaceName()) : null; + + if ($docComment === false) { + return []; + } + + $returnTags = $docBlockFactory + ->create($docComment, $context) + ->getTagsByName('return'); + + $types = []; + + foreach ($returnTags as $returnTag) { + /** @var Return_ $returnTag */ + $returnTypes = explode('|', (string)$returnTag->getType()); + + foreach ($returnTypes as $returnType) { + $type = $typeResolver->resolve($returnType, $context); + $types[] = $type; + } + } + + return $types; + } + + public static function getDocBlockTypes(ReflectionParameter|ReflectionProperty|\PHPStan\BetterReflection\Reflection\ReflectionParameter $reflection): array + { + $docBlockFactory = DocBlockFactory::createInstance(); + $typeResolver = new TypeResolver(); + + if ($reflection instanceof ReflectionProperty) { + $docComment = $reflection->getDocComment(); + $context = new Context($reflection->getDeclaringClass()->getNamespaceName()); + + } else { + $docComment = $reflection->getDeclaringFunction()->getDocComment(); + $namespace = $reflection->getDeclaringFunction()->getNamespaceName(); + $context = $namespace ? new Context($reflection->getDeclaringFunction()->getNamespaceName()) : null; + } + + if ($docComment === false) { + return []; + } + + $paramTags = $docBlockFactory + ->create($docComment, $context) + ->getTagsByName('param'); + + $types = []; + + foreach ($paramTags as $paramTag) { + /** @var \phpDocumentor\Reflection\DocBlock\Tags\Param $paramTag */ + $paramTypes = explode('|', (string)$paramTag->getType()); + + foreach ($paramTypes as $paramType) { + $type = $typeResolver->resolve($paramType, $context); + $types[] = $type; + } + } + + return $types; + } + + /** + * @throws \Exception + */ + public static function createReflectionMethodFromName(string $className, string $methodName): ReflectionMethod + { + try { + return self::createClassFromName($className)->getMethod($methodName); + } catch (\ReflectionException) { + throw new \Exception(sprintf('Could not find class: %s', $className)); + } + } + + /** + * @throws \Exception + */ + public static function createReflectionFunctionFromName(string $functionName): \PHPStan\BetterReflection\Reflection\ReflectionFunction + { + return (new BetterReflection())->reflector()->reflectFunction($functionName); + } + + /** + * @throws \ReflectionException + */ + public static function createClassFromName(string $className): ReflectionClass + { + return new ReflectionClass($className); + } + + /** + * @throws \ReflectionException + */ + public static function createFunctionFromClosure(\Closure $closure): ReflectionFunction + { + return new ReflectionFunction($closure); + } + + public static function createClassFromInstance(object $instance): ReflectionClass + { + return new ReflectionClass($instance); + } + + public static function createPropertyFromName(string $className, string $propertyName): ReflectionProperty + { + return self::createClassFromName($className)->getProperty($propertyName); + } + + public static function createPropertyFromInstance(object $instance, string $propertyName): ReflectionProperty + { + return self::createClassFromInstance($instance)->getProperty($propertyName); + } + + /** + * @throws \ReflectionException + */ + public static function createParameterFromInstanceAndMethod(object $instance, string $methodName, string $parameterName): ReflectionParameter + { + $parameters = self::createClassFromInstance($instance)->getMethod($methodName)->getParameters(); + + foreach ($parameters as $parameter) { + if ($parameter->getName() === $parameterName) { + return $parameter; + } + } + + throw new \ReflectionException(sprintf('Could not find parameter: %s', $parameterName)); + } + + public static function createParameterFromClassNameAndMethod(string $className, string $methodName, string $parameterName): ReflectionParameter + { + $parameters = self::createClassFromName($className)->getMethod($methodName)->getParameters(); + + foreach ($parameters as $parameter) { + if ($parameter->getName() === $parameterName) { + return $parameter; + } + } + + throw new \ReflectionException(sprintf('Could not find parameter: %s', $parameterName)); + } +} diff --git a/src/PhpGenerator/Helper/Traits/MethodOverloadAwareTrait.php b/src/PhpGenerator/Helper/Traits/MethodOverloadAwareTrait.php index 1e72cac..6027ffa 100644 --- a/src/PhpGenerator/Helper/Traits/MethodOverloadAwareTrait.php +++ b/src/PhpGenerator/Helper/Traits/MethodOverloadAwareTrait.php @@ -4,8 +4,8 @@ namespace Sidux\PhpGenerator\Helper\Traits; -use Roave\BetterReflection\Reflection\ReflectionClass; use Sidux\PhpGenerator\Helper\PhpHelper; +use Sidux\PhpGenerator\Helper\ReflectionHelper; trait MethodOverloadAwareTrait { @@ -29,12 +29,12 @@ protected static function buildMethodNameWithArgsTypes(string $baseName, array $ foreach ($args as $i => $arg) { $type = \gettype($arg); if ('object' === $type) { - $class = ReflectionClass::createFromInstance($arg); + $class = ReflectionHelper::createClassFromInstance($arg); $types[$i][] = $class->getShortName(); $types[$i] = array_merge( $types[$i], $class->getInterfaceNames(), - $class->getParentClassNames() + [$class->getParentClass() ?? $class->getParentClass()->getName()] ); } $types[$i][] = $type; diff --git a/src/PhpGenerator/Model/Contract/TypeAware.php b/src/PhpGenerator/Model/Contract/TypeAware.php index 7622d22..e5fb7de 100644 --- a/src/PhpGenerator/Model/Contract/TypeAware.php +++ b/src/PhpGenerator/Model/Contract/TypeAware.php @@ -5,7 +5,6 @@ namespace Sidux\PhpGenerator\Model\Contract; use phpDocumentor\Reflection\Type as DocType; -use Roave\BetterReflection\Reflection\ReflectionType; use Sidux\PhpGenerator\Model\Type; interface TypeAware @@ -25,19 +24,19 @@ public function getTypeHint(): ?string; public function getTypes(): array; /** - * @param array $types + * @param array $types */ public function setTypes(array $types); public function isNullable(): bool; /** - * @param array $types + * @param array $types */ public function addTypes(array $types); /** - * @param null|string|NamespaceAware|Type|ReflectionType|DocType $type + * @param null|string|NamespaceAware|Type|\ReflectionType|DocType $type */ public function addType($type); } diff --git a/src/PhpGenerator/Model/Method.php b/src/PhpGenerator/Model/Method.php index 61d9a7b..ad3d62a 100644 --- a/src/PhpGenerator/Model/Method.php +++ b/src/PhpGenerator/Model/Method.php @@ -4,16 +4,18 @@ namespace Sidux\PhpGenerator\Model; -use Roave\BetterReflection\Reflection\ReflectionFunction; -use Roave\BetterReflection\Reflection\ReflectionMethod; +use ReflectionFunction; +use ReflectionMethod; use Sidux\PhpGenerator\Helper; +use Sidux\PhpGenerator\Helper\ReflectionHelper; use Sidux\PhpGenerator\Helper\StringHelper; use Sidux\PhpGenerator\Model\Contract\Element; use Sidux\PhpGenerator\Model\Contract\Member; use Sidux\PhpGenerator\Model\Contract\TypeAware; +use PHPStan\BetterReflection\Reflection\ReflectionFunction as BetterReflectionFunction; /** - * @method static self from(ReflectionMethod|ReflectionFunction|string|array $from) + * @method static self from(ReflectionMethod|ReflectionFunction|\ReflectionFunction|string|array $from) */ final class Method extends Member implements Element, TypeAware { @@ -45,6 +47,8 @@ final class Method extends Member implements Element, TypeAware */ private string $defaultParameterVisibility = Parameter::DEFAULT_VISIBILITY; + private bool $format = false; + public function __toString(): string { $this->validate(); @@ -59,9 +63,9 @@ public function __toString(): string $output .= $this->isReference() ? '&' : null; $output .= $this->getName(); $output .= '('; - $output .= $this->hasMoreThanTwoParameters() ? "\n" : null; - $output .= $this->hasMoreThanTwoParameters() ? StringHelper::indent(implode(",\n", $this->getParameters())) : implode(', ', $this->getParameters()); - $output .= $this->hasMoreThanTwoParameters() ? "\n" : null; + $output .= $this->isFormatted() ? "\n" : null; + $output .= $this->isFormatted() ? StringHelper::indent(implode(",\n", $this->getParameters())) : implode(', ', $this->getParameters()); + $output .= $this->isFormatted() ? "\n" : null; $output .= ')'; $output .= $this->getTypeHint() ? ': ' . $this->getTypeHint() : null; $output .= $this->hasBody() ? "\n{\n" : ";\n"; @@ -81,30 +85,33 @@ public static function create(string $name): self return new self($name); } + /** + * @throws \Exception + */ public static function fromArray(array $from): self { [$className, $methodName] = $from; if (\is_object($className)) { $className = $className::class; } - $ref = ReflectionMethod::createFromName($className, $methodName); + $ref = ReflectionHelper::createReflectionMethodFromName($className, $methodName); return self::fromReflectionMethod($ref); } - public static function fromReflectionFunction(ReflectionFunction $ref): self + public static function fromReflectionFunction(ReflectionFunction|BetterReflectionFunction $ref): self { $method = new self($ref->getName()); /** @var array $parameters */ $parameters = array_map(Parameter::class . '::from', $ref->getParameters()); $method->setParameters($parameters); $method->setVariadic($ref->isVariadic()); - $method->setBody($ref->getBodyCode()); + $method->setBody(ReflectionHelper::getBodyCode($ref)); $method->setReference($ref->returnsReference()); $method->setComment($ref->getDocComment()); if ($ref->hasReturnType()) { $method->addType($ref->getReturnType()); - $method->addTypes($ref->getDocBlockReturnTypes()); + $method->addTypes(ReflectionHelper::getDocBlockReturnTypes($ref)); } return $method; @@ -132,31 +139,34 @@ public static function fromReflectionMethod(ReflectionMethod $ref): self $method->setFinal($ref->isFinal()); $method->setAbstract($ref->isAbstract() && !$isInterface); - $method->setBody($ref->getBodyCode()); + $method->setBody(ReflectionHelper::getBodyCode($ref, $isInterface)); $method->setReference($ref->returnsReference()); - $method->setComment($ref->getDocComment()); + $method->setComment($ref->getDocComment() ?: null); if ($ref->hasReturnType()) { $method->addType($ref->getReturnType()); - $method->addTypes($ref->getDocBlockReturnTypes()); + $method->addTypes(ReflectionHelper::getDocBlockReturnTypes($ref)); } return $method; } + /** + * @throws \Exception + */ public static function fromString(string $from): self { $parts = explode('::', $from); if (2 === \count($parts)) { [$className, $methodName] = $parts; - $ref = ReflectionMethod::createFromName($className, $methodName); + $ref = ReflectionHelper::createReflectionMethodFromName($className, $methodName); return self::fromReflectionMethod($ref); } if (1 === \count($parts)) { [$methodName] = $parts; - $ref = ReflectionFunction::createFromName($methodName); + $ref = ReflectionHelper::createReflectionFunctionFromName($methodName); return self::fromReflectionFunction($ref); } @@ -215,6 +225,8 @@ public function getParameters(): array } /** + * @deprecated types are not resolved properly when using setParameters - this needs to be fixed in a later release. Use addParameter() instead. + * * @param Parameter[] $parameters */ public function setParameters(array $parameters): self @@ -238,6 +250,20 @@ public function setVariadic(bool $variadic = true): self return $this; } + public function setFormat(bool $format = true): self + { + if ($this->hasMoreThanTwoParameters()) { + $this->format = $format; + } + + return $this; + } + + public function isFormatted(): bool + { + return $this->format; + } + public function addBody(string $code): self { $this->body .= ($this->body ? "\n" : '') . $code; diff --git a/src/PhpGenerator/Model/Parameter.php b/src/PhpGenerator/Model/Parameter.php index 0b03e17..877724d 100644 --- a/src/PhpGenerator/Model/Parameter.php +++ b/src/PhpGenerator/Model/Parameter.php @@ -4,8 +4,9 @@ namespace Sidux\PhpGenerator\Model; -use Roave\BetterReflection\Reflection\ReflectionParameter; +use ReflectionParameter; use Sidux\PhpGenerator\Helper; +use Sidux\PhpGenerator\Helper\ReflectionHelper; use Sidux\PhpGenerator\Model\Contract\Element; use Sidux\PhpGenerator\Model\Contract\TypeAware; use Sidux\PhpGenerator\Model\Contract\ValueAware; @@ -40,9 +41,11 @@ public function getParent(): ?Method return $this->parent; } - public function setParent(?Method $parent): void + public function setParent(?Method $parent): self { $this->parent = $parent; + + return $this; } public static function create(string $name): self @@ -67,17 +70,17 @@ public function __toString(): string public static function fromArray(array $from): self { [$classInstance, $methodName, $parameterName] = $from; - $ref = ReflectionParameter::createFromClassInstanceAndMethod($classInstance, $methodName, $parameterName); + $ref = ReflectionHelper::createParameterFromInstanceAndMethod($classInstance, $methodName, $parameterName); return self::fromReflectionParameter($ref); } - public static function fromReflectionParameter(ReflectionParameter $ref): self + public static function fromReflectionParameter(ReflectionParameter|\PHPStan\BetterReflection\Reflection\ReflectionParameter $ref): self { $param = new self($ref->getName()); $param->setReference($ref->isPassedByReference()); $param->addType($ref->getType()); - $param->addTypes($ref->getDocBlockTypes()); + $param->addTypes(ReflectionHelper::getDocBlockTypes($ref)); if (!$ref->isVariadic() && ($ref->isOptional() || $ref->isDefaultValueAvailable())) { $param->setValue(new Value($ref->getDefaultValue(), $ref->isDefaultValueConstant())); } @@ -89,7 +92,7 @@ public static function fromReflectionParameter(ReflectionParameter $ref): self public static function fromString(string $from): self { [$className, $methodName, $parameterName] = explode('::', $from); - $ref = ReflectionParameter::createFromClassNameAndMethod($className, $methodName, $parameterName); + $ref = ReflectionHelper::createParameterFromClassNameAndMethod($className, $methodName, $parameterName); return self::fromReflectionParameter($ref); } @@ -128,7 +131,7 @@ public function getDefaultVisibility(): string public function setPromoted(): self { - if ($this->getParent() && $this->getParent()->getName() !== Method::CONSTRUCTOR) { + if ($this->getParent()?->getName() !== Method::CONSTRUCTOR) { throw new \RuntimeException('Promotion is only allowed for constructor parameters'); } diff --git a/src/PhpGenerator/Model/Part/TypeAwareTrait.php b/src/PhpGenerator/Model/Part/TypeAwareTrait.php index fd7040f..27123f2 100644 --- a/src/PhpGenerator/Model/Part/TypeAwareTrait.php +++ b/src/PhpGenerator/Model/Part/TypeAwareTrait.php @@ -5,7 +5,8 @@ namespace Sidux\PhpGenerator\Model\Part; use phpDocumentor\Reflection\Type as DocType; -use Roave\BetterReflection\Reflection\ReflectionType; +use PHPStan\BetterReflection\Reflection\ReflectionNamedType; +use ReflectionType; use Sidux\PhpGenerator\Model\Contract\NamespaceAware; use Sidux\PhpGenerator\Model\Contract\TypeAware; use Sidux\PhpGenerator\Model\Type; @@ -40,7 +41,12 @@ public function getDocTypes(): array public function getTypeHint(): ?string { $types = $this->getTypes(); - if (\count($types) > 2) { + + $types = array_map(function (Type $type) { + return $type->isCollection() ? $type . '[]' : $type; + }, $types); + + if (!isset($types[Type::NULL]) && \count($types) == 2 || \count($types) > 2) { return implode('|', $types); } @@ -124,7 +130,7 @@ public function addTypeFromPhpType(Type $type): self return $this; } - public function addTypeFromReflectionType(ReflectionType $ref): self + public function addTypeFromReflectionType(ReflectionType|ReflectionNamedType $ref): self { $type = Type::fromReflectionType($ref); @@ -176,7 +182,7 @@ public function addType($type): self return $this->addTypeFromString($type); } - if ($type instanceof ReflectionType) { + if ($type instanceof ReflectionType || $type instanceof \PHPStan\BetterReflection\Reflection\ReflectionType) { return $this->addTypeFromReflectionType($type); } diff --git a/src/PhpGenerator/Model/Property.php b/src/PhpGenerator/Model/Property.php index 567da4d..d7a1e26 100644 --- a/src/PhpGenerator/Model/Property.php +++ b/src/PhpGenerator/Model/Property.php @@ -4,8 +4,9 @@ namespace Sidux\PhpGenerator\Model; -use Roave\BetterReflection\Reflection\ReflectionProperty; +use ReflectionProperty; use Sidux\PhpGenerator\Helper; +use Sidux\PhpGenerator\Helper\ReflectionHelper; use Sidux\PhpGenerator\Model\Contract\Element; use Sidux\PhpGenerator\Model\Contract\Member; use Sidux\PhpGenerator\Model\Contract\TypeAware; @@ -48,7 +49,7 @@ public static function create(...$args): self public static function fromArray(array $from): self { - $ref = ReflectionProperty::createFromInstance($from[0], $from[1]); + $ref = ReflectionHelper::createPropertyFromInstance($from[0], $from[1]); return self::fromReflectionProperty($ref); } @@ -74,15 +75,22 @@ public static function fromPrototype(string $property): Property public static function fromReflectionProperty(ReflectionProperty $ref): self { $prop = new self($ref->getName()); - if ($ref->getAst()->props[0]->default) { + /* Why is prop1 checked? + * if ($ref->getDeclaringClass()->getProperties()['prop1']->getDefaultValue()) { $prop->setValue($ref->getDefaultValue()); - } + }*/ $prop->addType($ref->getType()); $prop->setStatic($ref->isStatic()); - foreach ($ref->getDocBlockTypes() as $type) { + foreach (Helper\ReflectionHelper::getDocBlockTypes($ref) as $type) { $prop->addType((string)$type); } - $prop->setComment($ref->getDocComment()); + $prop->setComment($ref->getDocComment() ?: null); + + $classInstance = $ref->getDeclaringClass()->newInstance(); + + if ($ref->hasType() && $ref->isInitialized($classInstance)) { + $prop->setValue($ref->getDefaultValue()); + } if ($ref->isPrivate()) { $prop->setVisibility(Struct::PRIVATE); @@ -98,7 +106,7 @@ public static function fromReflectionProperty(ReflectionProperty $ref): self public static function fromString(string $from): self { [$className, $propertyName] = explode('::', $from); - $ref = ReflectionProperty::createFromName($className, $propertyName); + $ref = ReflectionHelper::createPropertyFromName($className, $propertyName); return self::fromReflectionProperty($ref); } diff --git a/src/PhpGenerator/Model/Struct.php b/src/PhpGenerator/Model/Struct.php index 5bf2515..0e4d30f 100644 --- a/src/PhpGenerator/Model/Struct.php +++ b/src/PhpGenerator/Model/Struct.php @@ -4,13 +4,14 @@ namespace Sidux\PhpGenerator\Model; -use Roave\BetterReflection\BetterReflection; -use Roave\BetterReflection\Reflection\ReflectionClass; -use Roave\BetterReflection\Reflection\ReflectionObject; -use Roave\BetterReflection\Reflector\ClassReflector; -use Roave\BetterReflection\SourceLocator\Type\SingleFileSourceLocator; +use PHPStan\BetterReflection\BetterReflection; +use PHPStan\BetterReflection\Reflector\ClassReflector; +use PHPStan\BetterReflection\SourceLocator\Type\SingleFileSourceLocator; +use ReflectionClass; +use ReflectionObject; use Sidux\PhpGenerator\Helper; use Sidux\PhpGenerator\Helper\PhpHelper; +use Sidux\PhpGenerator\Helper\ReflectionHelper; use Sidux\PhpGenerator\Helper\StringHelper; use Sidux\PhpGenerator\Model\Contract\Element; use Sidux\PhpGenerator\Model\Contract\Member; @@ -195,19 +196,19 @@ public static function fromFile(string $fileName): self public static function fromObject(object $object): self { - $from = ReflectionClass::createFromInstance($object); + $from = ReflectionHelper::createClassFromInstance($object); return self::fromReflectionClass($from); } - public static function fromReflectionClass(ReflectionClass $from): self + public static function fromReflectionClass(ReflectionClass|\PHPStan\BetterReflection\Reflection\ReflectionClass $from): self { if ($from->isAnonymous()) { throw new \InvalidArgumentException('Anonymous classes are not supported.'); } $class = new self($from->getName()); - $class->setComment($from->getDocComment()); + $class->setComment($from->getDocComment() ?: null); if ($from->isTrait()) { $class->setType(self::_TRAIT); @@ -219,38 +220,42 @@ public static function fromReflectionClass(ReflectionClass $from): self $class->setFinal($from->isFinal() && $class->getType() === $class::_CLASS); $class->setAbstract($from->isAbstract() && $class->getType() === $class::_CLASS); - $interfaces = []; - //bug fix getImmediateInterfaces should not return parent interfaces - foreach ($from->getImmediateInterfaces() as $interface) { - foreach ($interfaces as $implement) { - if ($implement->implementsInterface($interface->getName())) { - continue 2; + $alreadyImplemented = []; + $implements = $from->getInterfaces(); + $extend = $from->getParentClass(); + $parents = array_merge($implements, $extend ? [$extend] : []); + + foreach ($parents as $parent) { + if ($parent->getInterfaces() !== []) { + foreach ($parent->getInterfaces() as $interface) { + $alreadyImplemented[$interface->getName()] = $interface; } } - $interfaces[$interface->getName()] = $interface; } + $interfaces = array_diff_key($implements, $alreadyImplemented); $class->setImplements(array_keys($interfaces)); - $parent = $from->getParentClass(); - if ($parent) { - $class->setExtends([$parent->getName()]); + if ($extend) { + $class->setExtends([$extend->getName()]); } $props = []; - foreach ($from->getImmediateProperties() as $prop) { - if ($prop->isDefault()) { + foreach ($from->getProperties() as $prop) { + if ($prop->isDefault() && $from->getName() === $prop->getDeclaringClass()->getName()) { $props[] = Property::from($prop); } } $class->setProperties($props); $methods = []; - foreach ($from->getImmediateMethods() as $method) { - $methods[] = Method::from($method); + foreach ($from->getMethods() as $method) { + if ($from->getName() === $method->getDeclaringClass()->getName()) { + $methods[] = Method::from($method); + } } $class->setMethods($methods); - $class->setConstants($from->getImmediateConstants()); + $class->setConstants($from->getConstants()); return $class; } @@ -262,7 +267,7 @@ public static function fromReflectionObject(ReflectionObject $from): self public static function fromString(string $className): self { - $from = ReflectionClass::createFromName($className); + $from = ReflectionHelper::createClassFromName($className); return self::fromReflectionClass($from); } diff --git a/src/PhpGenerator/Model/Type.php b/src/PhpGenerator/Model/Type.php index 054af8e..3281544 100644 --- a/src/PhpGenerator/Model/Type.php +++ b/src/PhpGenerator/Model/Type.php @@ -4,7 +4,8 @@ namespace Sidux\PhpGenerator\Model; -use Roave\BetterReflection\Reflection\ReflectionType; +use PHPStan\BetterReflection\Reflection\ReflectionNamedType; +use ReflectionType; use Sidux\PhpGenerator\Helper; use Sidux\PhpGenerator\Helper\PhpHelper; use Sidux\PhpGenerator\Model\Contract\Element; @@ -82,6 +83,9 @@ public function __construct($type) if (\in_array($type, self::INTERNAL_TYPES, true)) { $this->internal = true; } + if (preg_match('/<.*>/', $type)) { + $type = preg_replace('/<.*>/', '', $type); + } $this->setQualifiedName($type); } @@ -100,11 +104,17 @@ public static function create(...$args): self return new self(...$args); } - public static function fromReflectionType(ReflectionType $ref): self + public static function fromReflectionType(ReflectionType|ReflectionNamedType $ref): self { $name = (string)$ref; if (!$ref->isBuiltin() && !str_contains($name, '\\')) { - $name = '\\' . $name; + $prefix = ''; + + if (str_contains($name, '?')) { + $prefix = '?'; + $name = str_replace($prefix, '', $name); + } + $name = $prefix . '\\' . $name; } $type = self::create($name); $type->internal = $ref->isBuiltin(); diff --git a/tests/PhpGenerator/Expected/ClassType.from.74.expect b/tests/PhpGenerator/Expected/ClassType.from.74.expect index 9ef9021..2e018ba 100644 --- a/tests/PhpGenerator/Expected/ClassType.from.74.expect +++ b/tests/PhpGenerator/Expected/ClassType.from.74.expect @@ -8,7 +8,7 @@ class Class7 { public \A $a; - public ?\B $b; + public ?\B $b = null; public ?\C $c = null; diff --git a/tests/PhpGenerator/Expected/ClassType.from.expect b/tests/PhpGenerator/Expected/ClassType.from.expect index f03b298..8bccd84 100644 --- a/tests/PhpGenerator/Expected/ClassType.from.expect +++ b/tests/PhpGenerator/Expected/ClassType.from.expect @@ -75,7 +75,7 @@ namespace Sidux\PhpGenerator\Stub; */ class Class5 { - public function func1(A $a, ?B $b, ?\C $c = null, ?\D $d = null, \E $e, ?int $i = 1, ?array $arr = []) + public function func1(A $a, ?B $b, \E $e, ?\C $c = null, ?\D $d = null, ?int $i = 1, ?array $arr = []) { } diff --git a/tests/PhpGenerator/Model/MethodTest.php b/tests/PhpGenerator/Model/MethodTest.php index 66aeb69..b30df92 100644 --- a/tests/PhpGenerator/Model/MethodTest.php +++ b/tests/PhpGenerator/Model/MethodTest.php @@ -5,9 +5,8 @@ namespace Sidux\PhpGenerator\Model; use PHPUnit\Framework\TestCase; -use Roave\BetterReflection\Reflection\ReflectionFunction; -use Roave\BetterReflection\Reflection\ReflectionMethod; use Sidux\PhpGenerator\Assert; +use Sidux\PhpGenerator\Helper\ReflectionHelper; use Sidux\PhpGenerator\Helper\StubHelper; use Sidux\PhpGenerator\Stub\D; use Sidux\PhpGenerator\Stub\InterfaceStub1; @@ -19,22 +18,22 @@ final class MethodTest extends TestCase /** * @test - * @throws \ReflectionException */ public function from(): void { - $res = Method::from(ReflectionMethod::createFromName(self::class, 'from')); + $res = Method::from(ReflectionHelper::createReflectionMethodFromName(self::class, 'from')); Assert::assertInstanceOf(Method::class, $res); Assert::assertSame('from', $res->getName()); - $res = Method::from(ReflectionFunction::createFromName('trim')); + $res = Method::from(ReflectionHelper::createReflectionFunctionFromName('trim')); + Assert::assertInstanceOf(Method::class, $res); Assert::assertSame('trim', $res->getName()); Assert::assertException( static function () { Method::from( - ReflectionFunction::createFromClosure( + ReflectionHelper::createFunctionFromClosure( static function () { } ) @@ -262,6 +261,5 @@ public function fromName(): void $content = StubHelper::load('functionStub1'); $function = Method::from('functionStub1'); Assert::assertSame($content, (string)$function); - } } diff --git a/tests/PhpGenerator/Model/ParameterTest.php b/tests/PhpGenerator/Model/ParameterTest.php index 5aa440f..337dbce 100644 --- a/tests/PhpGenerator/Model/ParameterTest.php +++ b/tests/PhpGenerator/Model/ParameterTest.php @@ -6,6 +6,7 @@ use PHPUnit\Framework\TestCase; use Sidux\PhpGenerator\Assert; +use Sidux\PhpGenerator\Stub\SubNamespace\PropertyTwo; class ParameterTest extends TestCase { @@ -51,15 +52,16 @@ public function dump(): void Assert::assertSame('?string $toto = null', (string)$param); $param->addType(TestCase::class); - Assert::assertSame('$toto = null', (string)$param); + Assert::assertSame('null|string|PHPUnit\Framework\TestCase $toto = null', (string)$param); $param->setInitialized(false); $param->setTypes(['iterable', TestCase::class . '[]']); - Assert::assertSame('iterable $toto', (string)$param); + Assert::assertSame('iterable|PHPUnit\Framework\TestCase[] $toto', (string)$param); $param->setReference(); - Assert::assertSame('iterable &$toto', (string)$param); + Assert::assertSame('iterable|PHPUnit\Framework\TestCase[] &$toto', (string)$param); + $param->setTypes(['iterable']); $param->setValue(null); Assert::assertSame('?iterable &$toto = null', (string)$param); @@ -68,5 +70,9 @@ public function dump(): void $param->removeType('null'); Assert::assertSame('iterable &$toto', (string)$param); + + $param->setReference(false); + $param->setTypes([PropertyTwo::class, TestCase::class]); + Assert::assertSame('Sidux\PhpGenerator\Stub\SubNamespace\PropertyTwo|PHPUnit\Framework\TestCase $toto', (string)$param); } } diff --git a/tests/PhpGenerator/Model/StructTest.php b/tests/PhpGenerator/Model/StructTest.php index 63b37fa..1a405e8 100644 --- a/tests/PhpGenerator/Model/StructTest.php +++ b/tests/PhpGenerator/Model/StructTest.php @@ -5,9 +5,8 @@ namespace Sidux\PhpGenerator\Model; use PHPUnit\Framework\TestCase; -use Roave\BetterReflection\Reflection\ReflectionClass; -use Roave\BetterReflection\Reflection\ReflectionObject; use Sidux\PhpGenerator\Assert; +use Sidux\PhpGenerator\Helper\ReflectionHelper; use Sidux\PhpGenerator\Helper\StubHelper; use Sidux\PhpGenerator\Stub\B; use Sidux\PhpGenerator\Stub\Class1; @@ -29,7 +28,7 @@ final class StructTest extends TestCase */ public function from(): void { - $res = Struct::from(ReflectionClass::createFromName(\stdClass::class)); + $res = Struct::from(ReflectionHelper::createClassFromName(\stdClass::class)); Assert::assertInstanceOf(Struct::class, $res); Assert::assertSame('stdClass', $res->getName()); @@ -37,7 +36,7 @@ public function from(): void Assert::assertException( static function () { Struct::from( - ReflectionObject::createFromInstance( + ReflectionHelper::createClassFromInstance( new class { } ) @@ -57,7 +56,7 @@ static function () { * @phpstan-ignore-next-line */ $obj->prop2 = 1; - $res[] = Struct::from(ReflectionObject::createFromInstance($obj)); + $res[] = Struct::from(ReflectionHelper::createClassFromInstance($obj)); $res[] = Struct::from(Class4::class); $res[] = Struct::from(Class5::class); $res[] = Struct::from(Class6::class); @@ -465,25 +464,32 @@ public function generate82Class(): void $objectClass = new Struct('PhpGenerator\Stub\SubNamespace\PropertyTwo'); $constructor = $class->addConstructor(); - $constructor->setParameters([ - Parameter::create('propertyOne') - ->addType('string') - ->setVisibility(Struct::PUBLIC) - ->setPromoted(), - Parameter::create('propertyTwo') - ->addType($objectClass) - ->setVisibility(Struct::PUBLIC) - ->setPromoted(), - Parameter::create('propertyThree') - ->addTypes(['string', 'array', 'null']) - ->setVisibility(Struct::PUBLIC) - ->setPromoted(), - Parameter::create('propertyFour') - ->addTypes(['string', 'null']) - ->setValue(null) - ->setVisibility(Struct::PUBLIC) - ->setPromoted(), - ]); + $constructor + ->addParameter('propertyOne') + ->addType('string') + ->setVisibility(Struct::PUBLIC) + ->setPromoted(); + + $constructor + ->addParameter('propertyTwo') + ->addType($objectClass) + ->setVisibility(Struct::PUBLIC) + ->setPromoted(); + + $constructor + ->addParameter('propertyThree') + ->addTypes(['string', 'array', 'null']) + ->setVisibility(Struct::PUBLIC) + ->setPromoted(); + + $constructor + ->addParameter('propertyFour') + ->addTypes(['string', 'null']) + ->setVisibility(Struct::PUBLIC) + ->setPromoted() + ->setValue(null); + + $constructor->setFormat(); Assert::assertExpect('ClassType.from.82.expect', $class); } diff --git a/tests/PhpGenerator/Stub/SubNamespace/PropertyTwo.php b/tests/PhpGenerator/Stub/SubNamespace/PropertyTwo.php index 1e0a01f..7ce97a0 100644 --- a/tests/PhpGenerator/Stub/SubNamespace/PropertyTwo.php +++ b/tests/PhpGenerator/Stub/SubNamespace/PropertyTwo.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PhpGenerator\Stub\SubNamespace; +namespace Sidux\PhpGenerator\Stub\SubNamespace; class PropertyTwo { From 34c67e1c179686fa850789ed7b5dda7d4a88f808 Mon Sep 17 00:00:00 2001 From: Christelle Canovas Date: Thu, 10 Oct 2024 17:48:37 +0200 Subject: [PATCH 6/6] chore(rector): Removed Rector --- composer.json | 1 - 1 file changed, 1 deletion(-) diff --git a/composer.json b/composer.json index 744ff52..a7428a2 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,6 @@ "phpstan/phpstan": "^1.10.56", "phpunit/phpcov": "^8.2", "phpunit/phpunit": "^9.2@dev", - "rector/rector": "^0.19.1", "roave/security-advisories": "dev-master", "symfony/var-dumper": "^5.2@dev", "symplify/changelog-linker": "^8.3",