Skip to content

Commit 9845ac7

Browse files
authored
Children_groups / Child_group feature (#49)
1 parent 5cc9a57 commit 9845ac7

File tree

19 files changed

+423
-146
lines changed

19 files changed

+423
-146
lines changed

.devcontainer/devcontainer.json

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,29 @@
88
"extensions": [
99
"bmewburn.vscode-intelephense-client",
1010
"xdebug.php-debug",
11-
"getpsalm.psalm-vscode-plugin"
11+
"SanderRonde.phpstan-vscode"
1212
],
1313
"settings": {
14-
"terminal.integrated.defaultProfile.linux": "bash"
14+
"terminal.integrated.defaultProfile.linux": "bash",
15+
"intelephense.telemetry.enabled": false,
16+
"workbench.colorCustomizations": {
17+
"statusBar.background": "#ffa600d3",
18+
"statusBar.noFolderBackground": "#ffa600d3",
19+
"statusBar.debuggingBackground": "#ffa600d3",
20+
"activityBar.activeBorder": "#ffa600d3",
21+
"activityBarBadge.background": "#ffa600d3",
22+
"badge.background": "#ffa600d3",
23+
"focusBorder": "#ffa600d3",
24+
"progressBar.background": "#ffa600d3",
25+
"notificationCenter.border": "#ffa600d3",
26+
"notificationsInfoIcon.foreground": "#ffa600d3",
27+
"pickerGroup.border": "#ffa600d3",
28+
"settings.modifiedItemIndicator": "#ffa600d3",
29+
"panelTitle.activeBorder": "#ffa600d3",
30+
"list.activeSelectionBackground": "#6e6e6e",
31+
"list.inactiveSelectionBackground": "#6e6e6e",
32+
"list.hoverBackground": "#6e6e6e",
33+
},
1534
}
1635
}
1736
},

.github/workflows/ci.yml

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,17 @@ on:
44
push:
55
pull_request:
66

7+
permissions:
8+
contents: read
9+
710
jobs:
811
lint:
912
name: Lint
1013
runs-on: ubuntu-latest
1114
steps:
12-
- uses: actions/checkout@v4
15+
- uses: actions/checkout@v5
16+
with:
17+
persist-credentials: false
1318

1419
- name: Setup PHP
1520
uses: shivammathur/setup-php@v2
@@ -37,7 +42,9 @@ jobs:
3742
name: Static Analysis
3843
runs-on: ubuntu-latest
3944
steps:
40-
- uses: actions/checkout@v4
45+
- uses: actions/checkout@v5
46+
with:
47+
persist-credentials: false
4148

4249
- name: Setup PHP
4350
uses: shivammathur/setup-php@v2
@@ -55,8 +62,8 @@ jobs:
5562
- name: Install dependencies
5663
run: composer install --prefer-dist --no-progress
5764

58-
- name: Run psalm
59-
run: vendor/bin/psalm
65+
- name: Run phpstan
66+
run: vendor/bin/phpstan analyse --memory-limit=2G
6067

6168
tests:
6269
name: PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, deps ${{ matrix.composer_args }}
@@ -74,6 +81,7 @@ jobs:
7481
symfony: '7.3'
7582
composer_args: '--prefer-stable'
7683
stability: 'stable'
84+
coverage: true
7785
- php: '8.4'
7886
symfony: '7.3'
7987
composer_args: '--prefer-lowest'
@@ -92,12 +100,15 @@ jobs:
92100
stability: 'dev'
93101

94102
steps:
95-
- uses: actions/checkout@v4
103+
- uses: actions/checkout@v5
104+
with:
105+
persist-credentials: false
96106

97107
- name: Setup PHP
98108
uses: shivammathur/setup-php@v2
99109
with:
100110
php-version: ${{ matrix.php }}
111+
coverage: pcov
101112

102113
- name: Cache Composer dependencies
103114
uses: actions/cache@v4
@@ -120,6 +131,18 @@ jobs:
120131

121132
- name: Install dependencies
122133
run: composer update ${{ matrix.composer_args }} --no-progress --no-scripts --no-plugins
123-
134+
124135
- name: Run phpunit
125-
run: vendor/bin/phpunit
136+
run: |
137+
if [[ "${{ matrix.coverage }}" == "true" ]]; then
138+
mkdir -p build/logs
139+
vendor/bin/phpunit --coverage-clover coverage.xml
140+
else
141+
vendor/bin/phpunit
142+
fi
143+
144+
- name: Upload coverage to Codecov
145+
if: matrix.coverage
146+
uses: codecov/codecov-action@v5
147+
with:
148+
token: ${{ secrets.CODECOV_TOKEN }}

README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
[![Total Downloads](https://poser.pugx.org/a2lix/auto-form-bundle/downloads)](https://packagist.org/packages/a2lix/auto-form-bundle)
66
[![License](https://poser.pugx.org/a2lix/auto-form-bundle/license)](https://packagist.org/packages/a2lix/auto-form-bundle)
77
[![Build Status](https://github.com/a2lix/AutoFormBundle/actions/workflows/ci.yml/badge.svg)](https://github.com/a2lix/AutoFormBundle/actions/workflows/ci.yml)
8+
[![codecov](https://codecov.io/gh/a2lix/AutoFormBundle/branch/main/graph/badge.svg)](https://codecov.io/gh/a2lix/AutoFormBundle)
89

910
Stop writing boilerplate form code. This bundle provides a single, powerful `AutoType` form type that automatically generates a complete Symfony form from any PHP class.
1011

@@ -135,6 +136,58 @@ class Product
135136
}
136137
```
137138

139+
### Conditional Fields with Groups
140+
141+
You can conditionally include fields based on groups, similar to how Symfony's `validation_groups` work. This is useful for having different versions of a form (e.g., a "creation" version vs. an "edition" version).
142+
143+
To enable this, pass a `children_groups` option to your form. This option specifies which groups of fields should be included.
144+
145+
```php
146+
$form = $this->createForm(AutoType::class, $product, [
147+
'children_groups' => ['product:edit'],
148+
]);
149+
```
150+
151+
You can then assign fields to one or more groups using either form options or attributes.
152+
153+
#### Via Form Options
154+
155+
Use the `child_groups` option within the `children` configuration:
156+
157+
```php
158+
// ...
159+
'children' => [
160+
'name' => [
161+
'child_groups' => ['product:edit', 'product:create'],
162+
],
163+
'stock' => [
164+
'child_groups' => ['product:edit'],
165+
],
166+
],
167+
// ...
168+
```
169+
170+
In this example, if `children_groups` is set to `['product:edit']`, both `name` and `stock` will be included. If it's set to `['product:create']`, only `name` will be included.
171+
172+
#### Via `#[AutoTypeCustom]` Attribute
173+
174+
Use the `groups` property on the attribute:
175+
176+
```php
177+
use A2lix\AutoFormBundle\Form\Attribute\AutoTypeCustom;
178+
179+
class Product
180+
{
181+
#[AutoTypeCustom(groups: ['product:edit', 'product:create'])]
182+
public ?string $name = null;
183+
184+
#[AutoTypeCustom(groups: ['product:edit'])]
185+
public ?int $stock = null;
186+
}
187+
```
188+
189+
If no `children_groups` option is provided to the form, all fields are included by default, regardless of whether they have groups assigned.
190+
138191
## Advanced Recipes
139192

140193
### Creating a Compound Field with `inherit_data`

composer.json

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,17 @@
2929
"doctrine/orm": "^3.5",
3030
"friendsofphp/php-cs-fixer": "^3.87",
3131
"kubawerlos/php-cs-fixer-custom-fixers": "^3.34",
32+
"phpstan/extension-installer": "^1.4",
33+
"phpstan/phpstan": "^2.0",
34+
"phpstan/phpstan-phpunit": "^2.0",
35+
"phpstan/phpstan-strict-rules": "^2.0",
36+
"phpstan/phpstan-symfony": "^2.0",
3237
"phpunit/phpunit": "^12.3",
3338
"rector/rector": "^2.1",
3439
"symfony/cache": "^7.3",
3540
"symfony/doctrine-bridge": "^7.3",
3641
"symfony/validator": "^7.3",
37-
"symfony/var-dumper": "^7.3",
38-
"vimeo/psalm": "^6.13"
42+
"symfony/var-dumper": "^7.3"
3943
},
4044
"suggest": {
4145
"a2lix/translation-form-bundle": "For translation form"
@@ -44,8 +48,8 @@
4448
"cs-fixer": [
4549
"php-cs-fixer fix --verbose"
4650
],
47-
"psalm": [
48-
"psalm"
51+
"phpstan": [
52+
"phpstan analyse --memory-limit=2G"
4953
],
5054
"phpunit": [
5155
"phpunit"
@@ -54,7 +58,8 @@
5458
"config": {
5559
"sort-packages": true,
5660
"allow-plugins": {
57-
"composer/package-versions-deprecated": true
61+
"composer/package-versions-deprecated": true,
62+
"phpstan/extension-installer": true
5863
}
5964
},
6065
"autoload": {

phpstan.neon

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
parameters:
2+
level: 10
3+
paths:
4+
- src
5+
- tests
6+
excludePaths:
7+
- src/A2lixAutoFormBundle.php
8+
- tests/Fixtures/*
9+
10+
# Stricter setup
11+
checkTooWideReturnTypesInProtectedAndPublicMethods: true
12+
checkUninitializedProperties: true
13+
rememberPossiblyImpureFunctionValues: false
14+
checkBenevolentUnionTypes: true
15+
#reportPossiblyNonexistentGeneralArrayOffset: true
16+
reportPossiblyNonexistentConstantArrayOffset: true
17+
reportAlwaysTrueInLastCondition: true
18+
reportAnyTypeWideningInVarTag: true
19+
checkMissingOverrideMethodAttribute: true
20+
checkMissingCallableSignature: true

psalm.xml

Lines changed: 0 additions & 37 deletions
This file was deleted.

src/A2lixAutoFormBundle.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ final class A2lixAutoFormBundle extends AbstractBundle
2121
#[\Override]
2222
public function configure(DefinitionConfigurator $definition): void
2323
{
24-
/** @psalm-suppress UndefinedMethod */
25-
/** @psalm-suppress MixedMethodCall */
2624
$definition->rootNode()
2725
->children()
2826
->arrayNode('children_excluded')

src/Form/Attribute/AutoTypeCustom.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,37 +11,41 @@
1111

1212
namespace A2lix\AutoFormBundle\Form\Attribute;
1313

14-
use A2lix\AutoFormBundle\Form\Type\AutoType;
14+
use A2lix\AutoFormBundle\Form\Builder\AutoTypeBuilder;
1515

1616
/**
17-
* @psalm-import-type ChildOptions from AutoType
17+
* @phpstan-import-type ChildOptions from AutoTypeBuilder
1818
*/
1919
#[\Attribute(\Attribute::TARGET_PROPERTY)]
2020
final readonly class AutoTypeCustom
2121
{
2222
/**
2323
* @param array<string, mixed> $options
2424
* @param class-string|null $type
25+
* @param list<string>|null $groups
2526
*/
2627
public function __construct(
2728
private array $options = [],
2829
private ?string $type = null,
2930
private ?string $name = null,
3031
private ?bool $excluded = null,
3132
private ?bool $embedded = null,
33+
private ?array $groups = null,
3234
) {}
3335

3436
/**
3537
* @return ChildOptions
3638
*/
3739
public function getOptions(): array
3840
{
41+
/** @var ChildOptions */
3942
return [
4043
...$this->options,
4144
...(null !== $this->type ? ['child_type' => $this->type] : []),
4245
...(null !== $this->name ? ['child_name' => $this->name] : []),
4346
...(null !== $this->excluded ? ['child_excluded' => $this->excluded] : []),
4447
...(null !== $this->embedded ? ['child_embedded' => $this->embedded] : []),
48+
...(null !== $this->groups ? ['child_groups' => $this->groups] : []),
4549
];
4650
}
4751
}

0 commit comments

Comments
 (0)