From 4b56d455e126187496877b23a8b8f11ef8be5d04 Mon Sep 17 00:00:00 2001 From: Artyom Osepyan Date: Sat, 5 Sep 2026 01:06:52 +0300 Subject: [PATCH 1/3] test: cover multiline formatting of the modified returned array --- tests/PHPFileBuilderTest.php | 3 +++ tests/Support/OriginStructures/enum.php | 5 +++++ tests/Support/OriginStructures/trait.php | 12 ++++++++++++ .../PHPFileBuilderTest/add_imports_to_enum.php | 5 +++++ .../add_imports_to_enum_code_added.php | 5 +++++ .../PHPFileBuilderTest/add_imports_to_trait.php | 12 ++++++++++++ .../PHPFileBuilderTest/add_traits_to_enum.php | 5 +++++ .../PHPFileBuilderTest/add_traits_to_trait.php | 12 ++++++++++++ .../PHPFileBuilderTest/enum_method_removed.php | 5 +++++ .../enum_with_added_method.php | 5 +++++ .../enum_with_return_array_item_added.php | 5 +++++ tests/fixtures/PHPFileBuilderTest/trait.php | 12 ++++++++++++ .../PHPFileBuilderTest/trait_method_removed.php | 12 ++++++++++++ .../trait_with_added_method.php | 12 ++++++++++++ .../trait_with_method_code_added.php | 12 ++++++++++++ .../trait_with_return_array_item_added.php | 17 +++++++++++++++++ 16 files changed, 139 insertions(+) diff --git a/tests/PHPFileBuilderTest.php b/tests/PHPFileBuilderTest.php index cd19ce2..d2033e4 100644 --- a/tests/PHPFileBuilderTest.php +++ b/tests/PHPFileBuilderTest.php @@ -774,6 +774,8 @@ public function testAddReturnedArrayItemInTrait(): void new PHPFileBuilder($file) ->addReturnedArrayItem('getUserData', "['admin', 'editor']", 'roles') + ->addReturnedArrayItem('getDefaultFilters', 'is_published') + ->addReturnedArrayItem('getInlineOptions', '3', 'third') ->save(); } @@ -788,6 +790,7 @@ public function testAddReturnedArrayItemInEnum(): void new PHPFileBuilder($file) ->addReturnedArrayItem('updatableStatuses', 'self::Second') + ->addReturnedArrayItem('defaultStatuses', 'self::First') ->save(); } diff --git a/tests/Support/OriginStructures/enum.php b/tests/Support/OriginStructures/enum.php index fbb1fdb..de4bce6 100644 --- a/tests/Support/OriginStructures/enum.php +++ b/tests/Support/OriginStructures/enum.php @@ -12,6 +12,11 @@ public static function toArray(): array return self::cases(); } + public static function defaultStatuses(): array + { + return []; + } + public static function updatableStatuses(): array { return [self::First]; diff --git a/tests/Support/OriginStructures/trait.php b/tests/Support/OriginStructures/trait.php index 4edba6d..a1a26bf 100644 --- a/tests/Support/OriginStructures/trait.php +++ b/tests/Support/OriginStructures/trait.php @@ -36,6 +36,18 @@ public function method3() ]); } + protected function getInlineOptions(): array + { + return ['first' => 1, 'second' => 2]; + } + + protected function getDefaultFilters(): array + { + return [ + 'is_active', + ]; + } + protected function getUserData(): array { return [ diff --git a/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum.php b/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum.php index b079449..99a9992 100644 --- a/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum.php +++ b/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum.php @@ -16,6 +16,11 @@ public static function toArray(): array return self::cases(); } + public static function defaultStatuses(): array + { + return []; + } + 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 7e509fe..ec58772 100644 --- a/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum_code_added.php +++ b/tests/fixtures/PHPFileBuilderTest/add_imports_to_enum_code_added.php @@ -30,6 +30,11 @@ public static function toArray(): array return self::cases(); } + public static function defaultStatuses(): array + { + return []; + } + 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 44db74c..0b7cb05 100644 --- a/tests/fixtures/PHPFileBuilderTest/add_imports_to_trait.php +++ b/tests/fixtures/PHPFileBuilderTest/add_imports_to_trait.php @@ -39,6 +39,18 @@ public function method3() ]); } + protected function getInlineOptions(): array + { + return ['first' => 1, 'second' => 2]; + } + + protected function getDefaultFilters(): array + { + return [ + 'is_active', + ]; + } + protected function getUserData(): array { return [ diff --git a/tests/fixtures/PHPFileBuilderTest/add_traits_to_enum.php b/tests/fixtures/PHPFileBuilderTest/add_traits_to_enum.php index 1845d04..11b6732 100644 --- a/tests/fixtures/PHPFileBuilderTest/add_traits_to_enum.php +++ b/tests/fixtures/PHPFileBuilderTest/add_traits_to_enum.php @@ -20,6 +20,11 @@ public static function toArray(): array return self::cases(); } + public static function defaultStatuses(): array + { + return []; + } + 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 d61265a..9738482 100644 --- a/tests/fixtures/PHPFileBuilderTest/add_traits_to_trait.php +++ b/tests/fixtures/PHPFileBuilderTest/add_traits_to_trait.php @@ -43,6 +43,18 @@ public function method3() ]); } + protected function getInlineOptions(): array + { + return ['first' => 1, 'second' => 2]; + } + + protected function getDefaultFilters(): array + { + return [ + 'is_active', + ]; + } + protected function getUserData(): array { return [ diff --git a/tests/fixtures/PHPFileBuilderTest/enum_method_removed.php b/tests/fixtures/PHPFileBuilderTest/enum_method_removed.php index 7656102..13695c3 100644 --- a/tests/fixtures/PHPFileBuilderTest/enum_method_removed.php +++ b/tests/fixtures/PHPFileBuilderTest/enum_method_removed.php @@ -7,6 +7,11 @@ enum SomeEnum case First = 'first'; case Second = 'second'; + public static function defaultStatuses(): array + { + return []; + } + public static function updatableStatuses(): array { return [self::First]; diff --git a/tests/fixtures/PHPFileBuilderTest/enum_with_added_method.php b/tests/fixtures/PHPFileBuilderTest/enum_with_added_method.php index b98a70d..fb2a429 100644 --- a/tests/fixtures/PHPFileBuilderTest/enum_with_added_method.php +++ b/tests/fixtures/PHPFileBuilderTest/enum_with_added_method.php @@ -12,6 +12,11 @@ public static function toArray(): array return self::cases(); } + public static function defaultStatuses(): array + { + return []; + } + public static function updatableStatuses(): array { return [self::First]; diff --git a/tests/fixtures/PHPFileBuilderTest/enum_with_return_array_item_added.php b/tests/fixtures/PHPFileBuilderTest/enum_with_return_array_item_added.php index 46a8cb4..c3bdecd 100644 --- a/tests/fixtures/PHPFileBuilderTest/enum_with_return_array_item_added.php +++ b/tests/fixtures/PHPFileBuilderTest/enum_with_return_array_item_added.php @@ -12,6 +12,11 @@ public static function toArray(): array return self::cases(); } + public static function defaultStatuses(): array + { + return [self::First]; + } + public static function updatableStatuses(): array { return [self::First, self::Second]; diff --git a/tests/fixtures/PHPFileBuilderTest/trait.php b/tests/fixtures/PHPFileBuilderTest/trait.php index 72ca8be..5f34776 100644 --- a/tests/fixtures/PHPFileBuilderTest/trait.php +++ b/tests/fixtures/PHPFileBuilderTest/trait.php @@ -41,6 +41,18 @@ public function method3() ]); } + protected function getInlineOptions(): array + { + return ['first' => 1, 'second' => 2]; + } + + protected function getDefaultFilters(): array + { + return [ + 'is_active', + ]; + } + protected function getUserData(): array { return [ diff --git a/tests/fixtures/PHPFileBuilderTest/trait_method_removed.php b/tests/fixtures/PHPFileBuilderTest/trait_method_removed.php index 5f8c682..dd86f2a 100644 --- a/tests/fixtures/PHPFileBuilderTest/trait_method_removed.php +++ b/tests/fixtures/PHPFileBuilderTest/trait_method_removed.php @@ -26,6 +26,18 @@ public function method3() ]); } + protected function getInlineOptions(): array + { + return ['first' => 1, 'second' => 2]; + } + + protected function getDefaultFilters(): array + { + return [ + 'is_active', + ]; + } + protected function getUserData(): array { return [ diff --git a/tests/fixtures/PHPFileBuilderTest/trait_with_added_method.php b/tests/fixtures/PHPFileBuilderTest/trait_with_added_method.php index 36a4fcd..6b25ad9 100644 --- a/tests/fixtures/PHPFileBuilderTest/trait_with_added_method.php +++ b/tests/fixtures/PHPFileBuilderTest/trait_with_added_method.php @@ -36,6 +36,18 @@ public function method3() ]); } + protected function getInlineOptions(): array + { + return ['first' => 1, 'second' => 2]; + } + + protected function getDefaultFilters(): array + { + return [ + 'is_active', + ]; + } + protected function getUserData(): array { return [ diff --git a/tests/fixtures/PHPFileBuilderTest/trait_with_method_code_added.php b/tests/fixtures/PHPFileBuilderTest/trait_with_method_code_added.php index bf5f78c..ec69eb6 100644 --- a/tests/fixtures/PHPFileBuilderTest/trait_with_method_code_added.php +++ b/tests/fixtures/PHPFileBuilderTest/trait_with_method_code_added.php @@ -54,6 +54,18 @@ public function method3() ]); } + protected function getInlineOptions(): array + { + return ['first' => 1, 'second' => 2]; + } + + protected function getDefaultFilters(): array + { + return [ + 'is_active', + ]; + } + protected function getUserData(): array { return [ diff --git a/tests/fixtures/PHPFileBuilderTest/trait_with_return_array_item_added.php b/tests/fixtures/PHPFileBuilderTest/trait_with_return_array_item_added.php index 736aaea..427ccba 100644 --- a/tests/fixtures/PHPFileBuilderTest/trait_with_return_array_item_added.php +++ b/tests/fixtures/PHPFileBuilderTest/trait_with_return_array_item_added.php @@ -36,6 +36,23 @@ public function method3() ]); } + protected function getInlineOptions(): array + { + return [ + 'first' => 1, + 'second' => 2, + 'third' => 3, + ]; + } + + protected function getDefaultFilters(): array + { + return [ + 'is_active', + 'is_published', + ]; + } + protected function getUserData(): array { return [ From f4b5384fa79e9819f42d4e6cc1ca6e1066035c0b Mon Sep 17 00:00:00 2001 From: Artyom Osepyan Date: Mon, 7 Sep 2026 22:44:32 +0300 Subject: [PATCH 2/3] fix: preserve multiline style of the modified returned array refs: https://github.com/RonasIT/larabuilder/issues/71#issuecomment-5424638363 --- README.md | 3 ++ src/Enums/StatementAttributeEnum.php | 2 + src/Printer.php | 51 ++++++++++++++++++- .../MethodVisitors/AddReturnedArrayItem.php | 12 ++++- 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f82c0a6..f0855d2 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,9 @@ traits, and enums. Both `$value` and `$key` are passed as strings. A bare identifier (`logo`, `datetime`) is inserted as a string literal; anything else — `null`, `true`, `false`, numbers, `RoleEnum::class`, `self::Second`, `['admin', 'editor']` — is inserted as raw PHP code. +The formatting of the modified array follows two rules: an array that was already multiline stays multiline, and an +array that ends up with more than two items becomes multiline. Otherwise the original style is kept. + ```php new PHPFileBuilder(app_path('Models/User.php')) ->addReturnedArrayItem('casts', 'RoleEnum::class', 'role') // 'role' => RoleEnum::class diff --git a/src/Enums/StatementAttributeEnum.php b/src/Enums/StatementAttributeEnum.php index 0e4301f..459024b 100644 --- a/src/Enums/StatementAttributeEnum.php +++ b/src/Enums/StatementAttributeEnum.php @@ -7,4 +7,6 @@ enum StatementAttributeEnum: string case Parent = 'parent'; case Previous = 'previous'; case Comments = 'comments'; + case Modified = 'modified'; + case Multiline = 'multiline'; } diff --git a/src/Printer.php b/src/Printer.php index 61b17f8..8c3fe68 100644 --- a/src/Printer.php +++ b/src/Printer.php @@ -2,6 +2,7 @@ namespace RonasIT\Larabuilder; +use Illuminate\Support\Arr; use PhpParser\Node; use PhpParser\Node\Expr\Array_; use PhpParser\Node\PropertyItem; @@ -40,13 +41,59 @@ protected function removeDuplicateEmptyLines(string $code): string return preg_replace("/(\r?\n){3,}/", "\n\n", $code); } + protected function pArray( + array $nodes, + array $origNodes, + int &$pos, + int $indentAdjustment, + string $parentNodeClass, + string $subNodeName, + ?int $fixup, + ): ?string { + $modifiedArray = ($parentNodeClass === Array_::class && $subNodeName === 'items') + ? $this->findModifiedArray($nodes) + : null; + + if (!is_null($modifiedArray)) { + $isMultiline = $this->wasMultiline($origNodes, $pos) || count($nodes) > 2; + + $modifiedArray->setAttribute(StatementAttributeEnum::Multiline->value, $isMultiline); + + return null; + } + + return parent::pArray($nodes, $origNodes, $pos, $indentAdjustment, $parentNodeClass, $subNodeName, $fixup); + } + protected function pExpr_Array(Array_ $node): string { - if ($this->hasParentOfType($node, PropertyItem::class)) { + $isMultiline = $node->getAttribute(StatementAttributeEnum::Multiline->value); + + if ($this->hasParentOfType($node, PropertyItem::class) || $isMultiline === true) { return '[' . $this->pCommaSeparatedMultiline($node->items, true) . $this->nl . ']'; } - return parent::pExpr_Array($node); + return ($isMultiline === false) + ? '[' . $this->pCommaSeparated($node->items) . ']' + : parent::pExpr_Array($node); + } + + protected function findModifiedArray(array $items): ?Array_ + { + $modifiedItem = Arr::first( + $items, + fn (?Node $item) => $item?->getAttribute(StatementAttributeEnum::Modified->value) === true, + ); + + return $modifiedItem?->getAttribute(StatementAttributeEnum::Parent->value); + } + + protected function wasMultiline(array $origNodes, int $pos): bool + { + $firstItem = $origNodes[0] ?? null; + $endPos = $firstItem?->getStartTokenPos() ?? $this->origTokens->findRight($pos, ']'); + + return str_contains($this->origTokens->getTokenCode($pos, $endPos, 0), "\n"); } protected function hasParentOfType(Node $node, string $type): bool diff --git a/src/Visitors/MethodVisitors/AddReturnedArrayItem.php b/src/Visitors/MethodVisitors/AddReturnedArrayItem.php index c4cdc21..117f094 100644 --- a/src/Visitors/MethodVisitors/AddReturnedArrayItem.php +++ b/src/Visitors/MethodVisitors/AddReturnedArrayItem.php @@ -11,6 +11,7 @@ use PhpParser\Node\Scalar; use PhpParser\Node\Stmt\ClassLike; use PhpParser\Node\Stmt\Return_; +use RonasIT\Larabuilder\Enums\StatementAttributeEnum; use RonasIT\Larabuilder\Exceptions\MultipleReturnStatementsException; use RonasIT\Larabuilder\Exceptions\UnexpectedReturnTypeException; use RonasIT\Larabuilder\Nodes\PreformattedExpression; @@ -43,7 +44,7 @@ public function updateNode(Node $node): void } if (is_null($this->key)) { - $returnNode->expr->items[] = new ArrayItem($this->value); + $this->appendItem($returnNode->expr, new ArrayItem($this->value)); return; } @@ -56,7 +57,14 @@ public function updateNode(Node $node): void } } - $returnNode->expr->items[] = new ArrayItem($this->value, $this->key); + $this->appendItem($returnNode->expr, new ArrayItem($this->value, $this->key)); + } + + protected function appendItem(Array_ $array, ArrayItem $item): void + { + $item->setAttribute(StatementAttributeEnum::Modified->value, true); + + $array->items[] = $item; } protected function isSameKey(?Expr $itemKey): bool From 9ffa6c992155295a8d433e7c2e87ec03bb234146 Mon Sep 17 00:00:00 2001 From: Artyom Osepyan Date: Mon, 7 Sep 2026 22:56:19 +0300 Subject: [PATCH 3/3] docs: describe the formatting rule of the modified returned array --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f0855d2..242fd47 100644 --- a/README.md +++ b/README.md @@ -64,8 +64,8 @@ traits, and enums. Both `$value` and `$key` are passed as strings. A bare identifier (`logo`, `datetime`) is inserted as a string literal; anything else — `null`, `true`, `false`, numbers, `RoleEnum::class`, `self::Second`, `['admin', 'editor']` — is inserted as raw PHP code. -The formatting of the modified array follows two rules: an array that was already multiline stays multiline, and an -array that ends up with more than two items becomes multiline. Otherwise the original style is kept. +When an item is appended, the formatting of the array follows two rules: an array that was already multiline stays +multiline, and an array that grows past two items becomes multiline. Otherwise the original style is kept. ```php new PHPFileBuilder(app_path('Models/User.php'))