diff --git a/README.md b/README.md index 952a281..e56d042 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,17 @@ Add new `use TraitName;` statements to a class, trait, or enum. This method auto **Note:** Need to provide the full trait class name (FQCN); the method will import it automatically. +#### addItemToReturnArray + +Add or update an item in the array returned by a method. The method must have a single `return` statement with an array literal. If a key is given and already exists, its value is updated; otherwise the item is appended. Works with classes, traits, and enums. + +```php +new PHPFileBuilder(app_path('Models/User.php')) + ->addItemToReturnArray('casts', 'RoleEnum::class', 'role') + ->addItemToReturnArray('getAvailableRelations', 'logo') + ->save(); +``` + #### addMethod Add a new method to a class, trait, or enum. Throws `NodeAlreadyExistsException` if a method with the given name already exists. diff --git a/src/Builders/PHPFileBuilder.php b/src/Builders/PHPFileBuilder.php index 883a20a..37d8b57 100644 --- a/src/Builders/PHPFileBuilder.php +++ b/src/Builders/PHPFileBuilder.php @@ -7,12 +7,14 @@ use PhpParser\ParserFactory; use RonasIT\Larabuilder\DTO\MethodParamsList; use RonasIT\Larabuilder\Enums\AccessModifierEnum; +use RonasIT\Larabuilder\Enums\DefaultValue; use RonasIT\Larabuilder\Enums\InsertPositionEnum; use RonasIT\Larabuilder\Exceptions\InvalidPHPFileException; use RonasIT\Larabuilder\NodeTraverser; use RonasIT\Larabuilder\Printer; use RonasIT\Larabuilder\Visitors\AddImports; use RonasIT\Larabuilder\Visitors\AddTraits; +use RonasIT\Larabuilder\Visitors\MethodVisitors\AddItemToReturnArray; use RonasIT\Larabuilder\Visitors\MethodVisitors\AddMethod; use RonasIT\Larabuilder\Visitors\MethodVisitors\InsertCodeToMethod; use RonasIT\Larabuilder\Visitors\PropertyVisitors\AddArrayPropertyItem; @@ -94,6 +96,13 @@ public function addMethod( return $this; } + public function addItemToReturnArray(string $methodName, string $value, string|DefaultValue $key = DefaultValue::None): self + { + $this->traverser->addVisitor(new AddItemToReturnArray($methodName, $value, $key)); + + return $this; + } + public function insertCodeToMethod(string $methodName, string $code, InsertPositionEnum $position = InsertPositionEnum::End): self { $this->traverser->addVisitor(new InsertCodeToMethod($methodName, $code, $position)); diff --git a/src/Exceptions/MultipleReturnStatementsException.php b/src/Exceptions/MultipleReturnStatementsException.php new file mode 100644 index 0000000..2d4d16d --- /dev/null +++ b/src/Exceptions/MultipleReturnStatementsException.php @@ -0,0 +1,13 @@ +attributes); + + if ($this->isPlainStringValue($value)) { + $this->value = "'{$value}'"; + } else { + $this->value = Str::chopStart($this->value, 'value = trim($this->value); + $this->value = Str::chopEnd($this->value, ';'); + + $this->validatePHPCode($this->value); + } + } + + public function getSubNodeNames(): array + { + return ['value']; + } + + public function getType(): string + { + return 'Expr_PreformattedExpression'; + } + + protected function isPlainStringValue(string $value): bool + { + return preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', $value) === 1 + && !in_array(strtolower($value), ['null', 'true', 'false']); + } + + protected function validatePHPCode(string $code): void + { + try { + new ParserFactory()->createForHostVersion()->parse(""); + } catch (Error) { + throw new InvalidPHPCodeException($code); + } + } +} diff --git a/src/Printer.php b/src/Printer.php index f487f3e..61b17f8 100644 --- a/src/Printer.php +++ b/src/Printer.php @@ -11,6 +11,7 @@ use PhpParser\PrettyPrinter\Standard; use RonasIT\Larabuilder\Enums\StatementAttributeEnum; use RonasIT\Larabuilder\Nodes\PreformattedCode; +use RonasIT\Larabuilder\Nodes\PreformattedExpression; class Printer extends Standard { @@ -98,9 +99,19 @@ protected function shouldAddNewlineBeforeIfTypeSame(Node $node, string $type): b return $previousNode !== null && $previousNode instanceof $type; } + protected function pExpr_PreformattedExpression(PreformattedExpression $node): string + { + return $this->formatPreformattedCode($node->value); + } + protected function pStmt_PreformattedCode(PreformattedCode $node): string { - $value = $this->preparePreformattedCode($node->value); + return $this->formatPreformattedCode($node->value); + } + + private function formatPreformattedCode(string $value): string + { + $value = $this->preparePreformattedCode($value); $indentLength = strspn($value, " \t"); $indent = substr($value, 0, $indentLength); diff --git a/src/Visitors/MethodVisitors/AddItemToReturnArray.php b/src/Visitors/MethodVisitors/AddItemToReturnArray.php new file mode 100644 index 0000000..a4efa36 --- /dev/null +++ b/src/Visitors/MethodVisitors/AddItemToReturnArray.php @@ -0,0 +1,108 @@ +valueExpr = new PreformattedExpression($value); + $this->keyExpr = ($key === DefaultValue::None) ? null : new PreformattedExpression($key); + } + + public function shouldUpdateNode(Node $node): bool + { + $isTarget = $node instanceof ClassMethod && $this->methodName === $node->name->name; + + if ($isTarget) { + $this->hasTargetMethod = true; + } + + return $isTarget; + } + + public function updateNode(Node $node): void + { + $returnNodes = $this->findReturnsInScope($node->stmts ?? []); + + if (count($returnNodes) > 1) { + throw new MultipleReturnStatementsException($this->methodName); + } + + $returnNode = $returnNodes[0] ?? null; + + if (!$returnNode?->expr instanceof Array_) { + throw new UnexpectedReturnTypeException($this->methodName, 'array', $node->returnType?->toString()); + } + + if (empty($this->keyExpr)) { + $returnNode->expr->items[] = new ArrayItem($this->valueExpr); + + return; + } + + $printer = new Printer(); + + foreach ($returnNode->expr->items as $item) { + if ($item instanceof ArrayItem + && !empty($item->key) + && $printer->prettyPrintExpr($item->key) === $this->keyExpr->value + ) { + $item->value = $this->valueExpr; + + return; + } + } + + $returnNode->expr->items[] = new ArrayItem($this->valueExpr, $this->keyExpr); + } + + protected function findReturnsInScope(array $nodes): array + { + $returns = []; + + foreach ($nodes as $node) { + if ($node instanceof Return_) { + $returns[] = $node; + + continue; + } + + if ($node instanceof FunctionLike) { + continue; + } + + foreach ($node->getSubNodeNames() as $name) { + foreach (Arr::wrap($node->$name) as $child) { + if ($child instanceof Node) { + $returns = [...$returns, ...$this->findReturnsInScope([$child])]; + } + } + } + } + + return $returns; + } +} diff --git a/src/Visitors/MethodVisitors/BaseMethodVisitor.php b/src/Visitors/MethodVisitors/BaseMethodVisitor.php index 4aee7b4..386f09c 100644 --- a/src/Visitors/MethodVisitors/BaseMethodVisitor.php +++ b/src/Visitors/MethodVisitors/BaseMethodVisitor.php @@ -5,13 +5,28 @@ use PhpParser\Node\Stmt\Class_; use PhpParser\Node\Stmt\Enum_; use PhpParser\Node\Stmt\Trait_; +use RonasIT\Larabuilder\Exceptions\NodeNotExistException; use RonasIT\Larabuilder\Visitors\AbstractNodeVisitor; abstract class BaseMethodVisitor extends AbstractNodeVisitor { + protected bool $hasTargetMethod = false; + + public function __construct( + protected string $methodName, + ) { + } + protected array $allowedParentNodesTypes = [ Class_::class, Trait_::class, Enum_::class, ]; + + protected function updatableNodeNotFoundHook(): void + { + if (!$this->hasTargetMethod) { + throw new NodeNotExistException('Method', $this->methodName); + } + } } diff --git a/src/Visitors/MethodVisitors/InsertCodeToMethod.php b/src/Visitors/MethodVisitors/InsertCodeToMethod.php index f002476..7066e6d 100644 --- a/src/Visitors/MethodVisitors/InsertCodeToMethod.php +++ b/src/Visitors/MethodVisitors/InsertCodeToMethod.php @@ -7,14 +7,11 @@ use PhpParser\Node\Stmt\Nop; use RonasIT\Larabuilder\Contracts\UpdateNodeContract; use RonasIT\Larabuilder\Enums\InsertPositionEnum; -use RonasIT\Larabuilder\Exceptions\NodeNotExistException; use RonasIT\Larabuilder\Nodes\PreformattedCode; use RonasIT\Larabuilder\Support\StatementDuplicateChecker; class InsertCodeToMethod extends BaseMethodVisitor implements UpdateNodeContract { - protected bool $hasTargetMethod = false; - protected PreformattedCode $code; protected StatementDuplicateChecker $statementDuplicateChecker; @@ -23,6 +20,8 @@ public function __construct( string $code, protected InsertPositionEnum $insertPosition, ) { + parent::__construct($methodName); + $this->code = new PreformattedCode($code); $this->statementDuplicateChecker = new StatementDuplicateChecker(); } @@ -50,11 +49,4 @@ public function updateNode(Node $node): void ? [$this->code, ...$separator, ...$existingStmts] : [...$existingStmts, ...$separator, $this->code]; } - - protected function updatableNodeNotFoundHook(): void - { - if (!$this->hasTargetMethod) { - throw new NodeNotExistException('Method', $this->methodName); - } - } } diff --git a/tests/NodeInserterTest.php b/tests/NodeInserterTest.php index fd1278f..9502fb3 100644 --- a/tests/NodeInserterTest.php +++ b/tests/NodeInserterTest.php @@ -48,7 +48,7 @@ public function testInsertMixedNodes(): void new TraitUse([new Name('NewTrait')]), new ClassConst([new Const_('ANOTHER_CONST', new Int_(0))], Modifiers::PUBLIC), new TraitUse([new Name('AnotherTrait')]), - ], true); + ]); $this->assertSame( $this->getFixture('class_with_mixed_nodes_inserted.php'), diff --git a/tests/PHPFileBuilderTest.php b/tests/PHPFileBuilderTest.php index bf61fd4..a78c9ec 100644 --- a/tests/PHPFileBuilderTest.php +++ b/tests/PHPFileBuilderTest.php @@ -11,9 +11,11 @@ use RonasIT\Larabuilder\Exceptions\InvalidPHPCodeException; use RonasIT\Larabuilder\Exceptions\InvalidPHPFileException; use RonasIT\Larabuilder\Exceptions\InvalidStructureTypeException; +use RonasIT\Larabuilder\Exceptions\MultipleReturnStatementsException; use RonasIT\Larabuilder\Exceptions\NodeAlreadyExistsException; use RonasIT\Larabuilder\Exceptions\NodeNotExistException; use RonasIT\Larabuilder\Exceptions\UnexpectedPropertyTypeException; +use RonasIT\Larabuilder\Exceptions\UnexpectedReturnTypeException; use RonasIT\Larabuilder\Tests\Support\Traits\PHPFileBuilderTestMockTrait; class PHPFileBuilderTest extends TestCase @@ -678,4 +680,122 @@ public function testAddMethodNotClassTraitEnum(): void ->addMethod('store', 'return;') ->save(); } + + public function testAddItemToReturnArray(): void + { + $file = $this->generateOriginalStructurePath('class.php'); + + $this->mockNativeFunction( + 'RonasIT\Larabuilder\Builders', + $this->callFilePutContent($file, 'class_with_return_array_item_added.php'), + ); + + new PHPFileBuilder($file) + ->addItemToReturnArray('casts', 'datetime', 'created_at') + ->addItemToReturnArray('casts', 'RoleEnum::class', 'role') + ->addItemToReturnArray('casts', 'array', 'settings') + ->addItemToReturnArray('casts', 'null', 'deleted_at') + ->addItemToReturnArray('casts', 'true', 'is_active') + ->addItemToReturnArray('casts', 'false', 'is_archived') + ->addItemToReturnArray('getAvailableRelations', 'logo') + ->addItemToReturnArray('viaQueues', 'QueueEnum::Database', 'MailChannel::class') + ->save(); + } + + public function testAddItemToReturnArrayUpdatesExistingKey(): void + { + $file = $this->generateOriginalStructurePath('class.php'); + + $this->mockNativeFunction( + 'RonasIT\Larabuilder\Builders', + $this->callFilePutContent($file, 'class_with_return_array_item_updated.php'), + ); + + new PHPFileBuilder($file) + ->addItemToReturnArray('casts', 'encrypted', 'password') + ->save(); + } + + public function testAddItemToReturnArrayInTrait(): void + { + $file = $this->generateOriginalStructurePath('trait.php'); + + $this->mockNativeFunction( + 'RonasIT\Larabuilder\Builders', + $this->callFilePutContent($file, 'trait_with_return_array_item_added.php'), + ); + + new PHPFileBuilder($file) + ->addItemToReturnArray('getUserData', "['admin', 'editor']", 'roles') + ->save(); + } + + public function testAddItemToReturnArrayInEnum(): void + { + $file = $this->generateOriginalStructurePath('enum.php'); + + $this->mockNativeFunction( + 'RonasIT\Larabuilder\Builders', + $this->callFilePutContent($file, 'enum_with_return_array_item_added.php'), + ); + + new PHPFileBuilder($file) + ->addItemToReturnArray('updatableStatuses', 'self::Second') + ->save(); + } + + public function testAddItemToReturnArrayThrowsOnNonArrayReturn(): void + { + $file = $this->generateOriginalStructurePath('class.php'); + + $this->assertExceptionThrew(UnexpectedReturnTypeException::class, "Method 'someMethod' return value has unexpected type. Expected 'array', actual 'void'."); + + new PHPFileBuilder($file) + ->addItemToReturnArray('someMethod', 'value', 'key') + ->save(); + } + + public function testAddItemToReturnArrayThrowsOnMultipleReturnStatements(): void + { + $file = $this->generateOriginalStructurePath('class.php'); + + $this->assertExceptionThrew(MultipleReturnStatementsException::class, "Method 'getRelations' contains multiple return statements."); + + new PHPFileBuilder($file) + ->addItemToReturnArray('getRelations', 'admin') + ->save(); + } + + public function testAddItemToReturnArrayThrowsOnMethodNotFound(): void + { + $file = $this->generateOriginalStructurePath('class.php'); + + $this->assertExceptionThrew(NodeNotExistException::class, "Method 'noMethod' does not exist."); + + new PHPFileBuilder($file) + ->addItemToReturnArray('noMethod', 'value', 'key') + ->save(); + } + + public function testAddItemToReturnArrayNotClassTraitEnum(): void + { + $file = $this->generateOriginalStructurePath('interface.php'); + + $this->assertExceptionThrew(InvalidStructureTypeException::class, "'AddItemToReturnArray' operation may only be applied to: Class, Trait, Enum."); + + new PHPFileBuilder($file) + ->addItemToReturnArray('casts', 'datetime', 'created_at') + ->save(); + } + + public function testAddItemToReturnArrayInvalidCode(): void + { + $file = $this->generateOriginalStructurePath('class.php'); + + $this->assertExceptionThrew(InvalidPHPCodeException::class, 'Cannot parse provided code: \'??invalid\'.'); + + new PHPFileBuilder($file) + ->addItemToReturnArray('someMethod', '??invalid') + ->save(); + } } diff --git a/tests/Support/OriginStructures/class.php b/tests/Support/OriginStructures/class.php index 9e82639..88d20a7 100644 --- a/tests/Support/OriginStructures/class.php +++ b/tests/Support/OriginStructures/class.php @@ -17,7 +17,7 @@ public function __construct() { } - public function someMethod() + public function someMethod(): void { $a = 1; $b = 2; @@ -33,4 +33,46 @@ public function someMethod() Arr::map($arr, fn ($value) => str_replace('0', '1', $value)); } + + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } + + protected function getAvailableRelations(): array + { + return [ + 'comments', + 'tags', + ]; + } + + protected function getRelations(): array + { + if ($this->isGuest) { + return ['name' => 'Guest']; + } + + return [ + 'comments', + 'tags', + ]; + } + + public function viaQueues(): array + { + $shouldThrottle = function () { + return now()->isWeekend(); + }; + + return [ + ExpoChannel::class => $shouldThrottle + ? QueueEnum::Low + : QueueEnum::PushNotifications, + BroadcastChannel::class => QueueEnum::Broadcasts, + ]; + } } diff --git a/tests/Support/OriginStructures/enum.php b/tests/Support/OriginStructures/enum.php index 30c9900..fbb1fdb 100644 --- a/tests/Support/OriginStructures/enum.php +++ b/tests/Support/OriginStructures/enum.php @@ -4,11 +4,16 @@ enum SomeEnum { - case First; - case Second; + case First = 'first'; + case Second = 'second'; public static function toArray(): array { return self::cases(); } + + public static function updatableStatuses(): array + { + return [self::First]; + } } diff --git a/tests/Support/OriginStructures/trait.php b/tests/Support/OriginStructures/trait.php index b64f0b0..9e9b127 100644 --- a/tests/Support/OriginStructures/trait.php +++ b/tests/Support/OriginStructures/trait.php @@ -34,4 +34,12 @@ public function method3() 'value' => $value, ]); } + + protected function getUserData(): array + { + return [ + 'name' => 'John', + 'email' => 'john@example.com', + ]; + } } diff --git a/tests/fixtures/NodeInserterTest/class_with_mixed_nodes_inserted.php b/tests/fixtures/NodeInserterTest/class_with_mixed_nodes_inserted.php index 083ccda..f7f58c8 100644 --- a/tests/fixtures/NodeInserterTest/class_with_mixed_nodes_inserted.php +++ b/tests/fixtures/NodeInserterTest/class_with_mixed_nodes_inserted.php @@ -25,7 +25,7 @@ public function __construct() { } - public function someMethod() + public function someMethod(): void { $a = 1; $b = 2; @@ -42,6 +42,48 @@ public function someMethod() Arr::map($arr, fn ($value) => str_replace('0', '1', $value)); } + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } + + protected function getAvailableRelations(): array + { + return [ + 'comments', + 'tags', + ]; + } + + protected function getRelations(): array + { + if ($this->isGuest) { + return ['name' => 'Guest']; + } + + return [ + 'comments', + 'tags', + ]; + } + + public function viaQueues(): array + { + $shouldThrottle = function () { + return now()->isWeekend(); + }; + + return [ + ExpoChannel::class => $shouldThrottle + ? QueueEnum::Low + : QueueEnum::PushNotifications, + BroadcastChannel::class => QueueEnum::Broadcasts, + ]; + } + public function newMethod() { } diff --git a/tests/fixtures/PHPFileBuilderTest/add_imports_to_class.php b/tests/fixtures/PHPFileBuilderTest/add_imports_to_class.php index 71458e1..494093e 100644 --- a/tests/fixtures/PHPFileBuilderTest/add_imports_to_class.php +++ b/tests/fixtures/PHPFileBuilderTest/add_imports_to_class.php @@ -19,7 +19,7 @@ public function __construct() { } - public function someMethod() + public function someMethod(): void { $a = 1; $b = 2; @@ -35,4 +35,46 @@ public function someMethod() Arr::map($arr, fn ($value) => str_replace('0', '1', $value)); } + + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } + + protected function getAvailableRelations(): array + { + return [ + 'comments', + 'tags', + ]; + } + + protected function getRelations(): array + { + if ($this->isGuest) { + return ['name' => 'Guest']; + } + + return [ + 'comments', + 'tags', + ]; + } + + public function viaQueues(): array + { + $shouldThrottle = function () { + return now()->isWeekend(); + }; + + return [ + ExpoChannel::class => $shouldThrottle + ? QueueEnum::Low + : QueueEnum::PushNotifications, + BroadcastChannel::class => QueueEnum::Broadcasts, + ]; + } } diff --git a/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum.php b/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum.php index 112f4c0..b079449 100644 --- a/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum.php +++ b/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum.php @@ -8,11 +8,16 @@ enum SomeEnum { - case First; - case Second; + case First = 'first'; + case Second = 'second'; public static function toArray(): array { return self::cases(); } + + public static function updatableStatuses(): array + { + return [self::First]; + } } diff --git a/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum_code_added.php b/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum_code_added.php index f2c420b..7e509fe 100644 --- a/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum_code_added.php +++ b/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum_code_added.php @@ -4,8 +4,8 @@ enum SomeEnum { - case First; - case Second; + case First = 'first'; + case Second = 'second'; public static function toArray(): array { @@ -29,4 +29,9 @@ public static function toArray(): array return self::cases(); } + + public static function updatableStatuses(): array + { + return [self::First]; + } } diff --git a/tests/fixtures/PHPFileBuilderTest/add_imports_to_trait.php b/tests/fixtures/PHPFileBuilderTest/add_imports_to_trait.php index 67748a4..8d9f821 100644 --- a/tests/fixtures/PHPFileBuilderTest/add_imports_to_trait.php +++ b/tests/fixtures/PHPFileBuilderTest/add_imports_to_trait.php @@ -37,4 +37,12 @@ public function method3() 'value' => $value, ]); } + + protected function getUserData(): array + { + return [ + 'name' => 'John', + 'email' => 'john@example.com', + ]; + } } diff --git a/tests/fixtures/PHPFileBuilderTest/add_traits_to_class.php b/tests/fixtures/PHPFileBuilderTest/add_traits_to_class.php index b3c7958..4e90f05 100644 --- a/tests/fixtures/PHPFileBuilderTest/add_traits_to_class.php +++ b/tests/fixtures/PHPFileBuilderTest/add_traits_to_class.php @@ -20,7 +20,7 @@ public function __construct() { } - public function someMethod() + public function someMethod(): void { $a = 1; $b = 2; @@ -36,4 +36,46 @@ public function someMethod() Arr::map($arr, fn ($value) => str_replace('0', '1', $value)); } + + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } + + protected function getAvailableRelations(): array + { + return [ + 'comments', + 'tags', + ]; + } + + protected function getRelations(): array + { + if ($this->isGuest) { + return ['name' => 'Guest']; + } + + return [ + 'comments', + 'tags', + ]; + } + + public function viaQueues(): array + { + $shouldThrottle = function () { + return now()->isWeekend(); + }; + + return [ + ExpoChannel::class => $shouldThrottle + ? QueueEnum::Low + : QueueEnum::PushNotifications, + BroadcastChannel::class => QueueEnum::Broadcasts, + ]; + } } diff --git a/tests/fixtures/PHPFileBuilderTest/add_traits_to_enum.php b/tests/fixtures/PHPFileBuilderTest/add_traits_to_enum.php index ee85268..1845d04 100644 --- a/tests/fixtures/PHPFileBuilderTest/add_traits_to_enum.php +++ b/tests/fixtures/PHPFileBuilderTest/add_traits_to_enum.php @@ -12,11 +12,16 @@ enum SomeEnum use SecondTrait; use ThirdTrait; - case First; - case Second; + case First = 'first'; + case Second = 'second'; public static function toArray(): array { return self::cases(); } + + public static function updatableStatuses(): array + { + return [self::First]; + } } diff --git a/tests/fixtures/PHPFileBuilderTest/add_traits_to_trait.php b/tests/fixtures/PHPFileBuilderTest/add_traits_to_trait.php index f3ea240..756d4a6 100644 --- a/tests/fixtures/PHPFileBuilderTest/add_traits_to_trait.php +++ b/tests/fixtures/PHPFileBuilderTest/add_traits_to_trait.php @@ -41,4 +41,12 @@ public function method3() 'value' => $value, ]); } + + protected function getUserData(): array + { + return [ + 'name' => 'John', + 'email' => 'john@example.com', + ]; + } } diff --git a/tests/fixtures/PHPFileBuilderTest/class_unchanged.php b/tests/fixtures/PHPFileBuilderTest/class_unchanged.php index 9e82639..88d20a7 100644 --- a/tests/fixtures/PHPFileBuilderTest/class_unchanged.php +++ b/tests/fixtures/PHPFileBuilderTest/class_unchanged.php @@ -17,7 +17,7 @@ public function __construct() { } - public function someMethod() + public function someMethod(): void { $a = 1; $b = 2; @@ -33,4 +33,46 @@ public function someMethod() Arr::map($arr, fn ($value) => str_replace('0', '1', $value)); } + + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } + + protected function getAvailableRelations(): array + { + return [ + 'comments', + 'tags', + ]; + } + + protected function getRelations(): array + { + if ($this->isGuest) { + return ['name' => 'Guest']; + } + + return [ + 'comments', + 'tags', + ]; + } + + public function viaQueues(): array + { + $shouldThrottle = function () { + return now()->isWeekend(); + }; + + return [ + ExpoChannel::class => $shouldThrottle + ? QueueEnum::Low + : QueueEnum::PushNotifications, + BroadcastChannel::class => QueueEnum::Broadcasts, + ]; + } } diff --git a/tests/fixtures/PHPFileBuilderTest/class_with_added_protected_method.php b/tests/fixtures/PHPFileBuilderTest/class_with_added_protected_method.php index cb76da3..0977c85 100644 --- a/tests/fixtures/PHPFileBuilderTest/class_with_added_protected_method.php +++ b/tests/fixtures/PHPFileBuilderTest/class_with_added_protected_method.php @@ -17,7 +17,7 @@ public function __construct() { } - public function someMethod() + public function someMethod(): void { $a = 1; $b = 2; @@ -34,6 +34,48 @@ public function someMethod() Arr::map($arr, fn ($value) => str_replace('0', '1', $value)); } + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } + + protected function getAvailableRelations(): array + { + return [ + 'comments', + 'tags', + ]; + } + + protected function getRelations(): array + { + if ($this->isGuest) { + return ['name' => 'Guest']; + } + + return [ + 'comments', + 'tags', + ]; + } + + public function viaQueues(): array + { + $shouldThrottle = function () { + return now()->isWeekend(); + }; + + return [ + ExpoChannel::class => $shouldThrottle + ? QueueEnum::Low + : QueueEnum::PushNotifications, + BroadcastChannel::class => QueueEnum::Broadcasts, + ]; + } + protected function boot() { parent::boot(); diff --git a/tests/fixtures/PHPFileBuilderTest/class_with_added_static_method.php b/tests/fixtures/PHPFileBuilderTest/class_with_added_static_method.php index 2217618..507dd35 100644 --- a/tests/fixtures/PHPFileBuilderTest/class_with_added_static_method.php +++ b/tests/fixtures/PHPFileBuilderTest/class_with_added_static_method.php @@ -17,7 +17,7 @@ public function __construct() { } - public function someMethod() + public function someMethod(): void { $a = 1; $b = 2; @@ -34,6 +34,48 @@ public function someMethod() Arr::map($arr, fn ($value) => str_replace('0', '1', $value)); } + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } + + protected function getAvailableRelations(): array + { + return [ + 'comments', + 'tags', + ]; + } + + protected function getRelations(): array + { + if ($this->isGuest) { + return ['name' => 'Guest']; + } + + return [ + 'comments', + 'tags', + ]; + } + + public function viaQueues(): array + { + $shouldThrottle = function () { + return now()->isWeekend(); + }; + + return [ + ExpoChannel::class => $shouldThrottle + ? QueueEnum::Low + : QueueEnum::PushNotifications, + BroadcastChannel::class => QueueEnum::Broadcasts, + ]; + } + public static function create(): static { return new static(); diff --git a/tests/fixtures/PHPFileBuilderTest/class_with_new_properties.php b/tests/fixtures/PHPFileBuilderTest/class_with_new_properties.php index ce233c5..cf0931b 100644 --- a/tests/fixtures/PHPFileBuilderTest/class_with_new_properties.php +++ b/tests/fixtures/PHPFileBuilderTest/class_with_new_properties.php @@ -19,7 +19,7 @@ public function __construct() { } - public function someMethod() + public function someMethod(): void { $a = 1; $b = 2; @@ -35,4 +35,46 @@ public function someMethod() Arr::map($arr, fn ($value) => str_replace('0', '1', $value)); } + + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } + + protected function getAvailableRelations(): array + { + return [ + 'comments', + 'tags', + ]; + } + + protected function getRelations(): array + { + if ($this->isGuest) { + return ['name' => 'Guest']; + } + + return [ + 'comments', + 'tags', + ]; + } + + public function viaQueues(): array + { + $shouldThrottle = function () { + return now()->isWeekend(); + }; + + return [ + ExpoChannel::class => $shouldThrottle + ? QueueEnum::Low + : QueueEnum::PushNotifications, + BroadcastChannel::class => QueueEnum::Broadcasts, + ]; + } } diff --git a/tests/fixtures/PHPFileBuilderTest/class_with_return_array_item_added.php b/tests/fixtures/PHPFileBuilderTest/class_with_return_array_item_added.php new file mode 100644 index 0000000..83e34fa --- /dev/null +++ b/tests/fixtures/PHPFileBuilderTest/class_with_return_array_item_added.php @@ -0,0 +1,86 @@ +save(); + + $config = ['status' => true, 'version' => 1]; + + $db->table('users')->where('id', 1)->first(); + + Arr::map($arr, fn ($value) => str_replace('0', '1', $value)); + } + + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + 'created_at' => 'datetime', + 'role' => RoleEnum::class, + 'settings' => 'array', + 'deleted_at' => null, + 'is_active' => true, + 'is_archived' => false, + ]; + } + + protected function getAvailableRelations(): array + { + return [ + 'comments', + 'tags', + 'logo', + ]; + } + + protected function getRelations(): array + { + if ($this->isGuest) { + return ['name' => 'Guest']; + } + + return [ + 'comments', + 'tags', + ]; + } + + public function viaQueues(): array + { + $shouldThrottle = function () { + return now()->isWeekend(); + }; + + return [ + ExpoChannel::class => $shouldThrottle + ? QueueEnum::Low + : QueueEnum::PushNotifications, + BroadcastChannel::class => QueueEnum::Broadcasts, + MailChannel::class => QueueEnum::Database, + ]; + } +} diff --git a/tests/fixtures/PHPFileBuilderTest/class_with_return_array_item_updated.php b/tests/fixtures/PHPFileBuilderTest/class_with_return_array_item_updated.php new file mode 100644 index 0000000..dc13863 --- /dev/null +++ b/tests/fixtures/PHPFileBuilderTest/class_with_return_array_item_updated.php @@ -0,0 +1,78 @@ +save(); + + $config = ['status' => true, 'version' => 1]; + + $db->table('users')->where('id', 1)->first(); + + Arr::map($arr, fn ($value) => str_replace('0', '1', $value)); + } + + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'encrypted', + ]; + } + + protected function getAvailableRelations(): array + { + return [ + 'comments', + 'tags', + ]; + } + + protected function getRelations(): array + { + if ($this->isGuest) { + return ['name' => 'Guest']; + } + + return [ + 'comments', + 'tags', + ]; + } + + public function viaQueues(): array + { + $shouldThrottle = function () { + return now()->isWeekend(); + }; + + return [ + ExpoChannel::class => $shouldThrottle + ? QueueEnum::Low + : QueueEnum::PushNotifications, + BroadcastChannel::class => QueueEnum::Broadcasts, + ]; + } +} diff --git a/tests/fixtures/PHPFileBuilderTest/enum_with_added_method.php b/tests/fixtures/PHPFileBuilderTest/enum_with_added_method.php index db29c2d..b98a70d 100644 --- a/tests/fixtures/PHPFileBuilderTest/enum_with_added_method.php +++ b/tests/fixtures/PHPFileBuilderTest/enum_with_added_method.php @@ -4,14 +4,19 @@ enum SomeEnum { - case First; - case Second; + case First = 'first'; + case Second = 'second'; public static function toArray(): array { return self::cases(); } + public static function updatableStatuses(): array + { + return [self::First]; + } + public function &label(): string { return $this->name; diff --git a/tests/fixtures/PHPFileBuilderTest/enum_with_return_array_item_added.php b/tests/fixtures/PHPFileBuilderTest/enum_with_return_array_item_added.php new file mode 100644 index 0000000..46a8cb4 --- /dev/null +++ b/tests/fixtures/PHPFileBuilderTest/enum_with_return_array_item_added.php @@ -0,0 +1,19 @@ + $value, ]); } + + protected function getUserData(): array + { + return [ + 'name' => 'John', + 'email' => 'john@example.com', + ]; + } } diff --git a/tests/fixtures/PHPFileBuilderTest/trait_with_added_method.php b/tests/fixtures/PHPFileBuilderTest/trait_with_added_method.php index ba3fb23..5c0c0a3 100644 --- a/tests/fixtures/PHPFileBuilderTest/trait_with_added_method.php +++ b/tests/fixtures/PHPFileBuilderTest/trait_with_added_method.php @@ -35,6 +35,14 @@ public function method3() ]); } + protected function getUserData(): array + { + return [ + 'name' => 'John', + 'email' => 'john@example.com', + ]; + } + public function handle(): bool { return $this->process(); diff --git a/tests/fixtures/PHPFileBuilderTest/trait_with_method_code_added.php b/tests/fixtures/PHPFileBuilderTest/trait_with_method_code_added.php index cf8334d..d1eb0bc 100644 --- a/tests/fixtures/PHPFileBuilderTest/trait_with_method_code_added.php +++ b/tests/fixtures/PHPFileBuilderTest/trait_with_method_code_added.php @@ -52,4 +52,12 @@ public function method3() 'value' => $value, ]); } + + protected function getUserData(): array + { + return [ + 'name' => 'John', + 'email' => 'john@example.com', + ]; + } } diff --git a/tests/fixtures/PHPFileBuilderTest/trait_with_return_array_item_added.php b/tests/fixtures/PHPFileBuilderTest/trait_with_return_array_item_added.php new file mode 100644 index 0000000..8485f5f --- /dev/null +++ b/tests/fixtures/PHPFileBuilderTest/trait_with_return_array_item_added.php @@ -0,0 +1,46 @@ +with(Arr::get($filters, 'with', [])) + ->withCount(Arr::get($filters, 'with_count', [])) + ->searchQuery($filters) + ->filterByQuery(['name']) + ->getSearchResults(); + } + + public function method2() + { + return $this->with(Arr::get($filters, 'with', [])); + } + + public function method3() + { + return $this->repository->create([ + 'name' => $key, + 'value' => $value, + ]); + } + + protected function getUserData(): array + { + return [ + 'name' => 'John', + 'email' => 'john@example.com', + 'roles' => ['admin', 'editor'], + ]; + } +}