Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit f45b9ce

Browse files
Support specifying type of data_class in forms
1 parent 1da7bf4 commit f45b9ce

File tree

9 files changed

+159
-2
lines changed

9 files changed

+159
-2
lines changed

‎extension.neon‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ parameters:
1313
consoleApplicationLoader: null
1414
featureToggles:
1515
skipCheckGenericClasses:
16+
- Symfony\Component\Form\AbstractType
17+
- Symfony\Component\Form\FormInterface
18+
- Symfony\Component\Form\FormTypeExtensionInterface
19+
- Symfony\Component\Form\FormTypeInterface
1620
- Symfony\Component\OptionsResolver\Options
1721
- Symfony\Component\Security\Core\Authorization\Voter\Voter
1822
- Symfony\Component\Security\Core\User\PasswordUpgraderInterface
@@ -36,13 +40,15 @@ parameters:
3640
- stubs/Symfony/Component/EventDispatcher/EventDispatcherInterface.stub
3741
- stubs/Symfony/Component/EventDispatcher/EventSubscriberInterface.stub
3842
- stubs/Symfony/Component/EventDispatcher/GenericEvent.stub
43+
- stubs/Symfony/Component/Form/AbstractType.stub
3944
- stubs/Symfony/Component/Form/ChoiceList/Loader/ChoiceLoaderInterface.stub
4045
- stubs/Symfony/Component/Form/Exception/ExceptionInterface.stub
4146
- stubs/Symfony/Component/Form/Exception/RuntimeException.stub
4247
- stubs/Symfony/Component/Form/Exception/TransformationFailedException.stub
4348
- stubs/Symfony/Component/Form/DataTransformerInterface.stub
4449
- stubs/Symfony/Component/Form/FormBuilderInterface.stub
4550
- stubs/Symfony/Component/Form/FormInterface.stub
51+
- stubs/Symfony/Component/Form/FormFactoryInterface.stub
4652
- stubs/Symfony/Component/Form/FormTypeExtensionInterface.stub
4753
- stubs/Symfony/Component/Form/FormTypeInterface.stub
4854
- stubs/Symfony/Component/Form/FormView.stub
@@ -52,6 +58,7 @@ parameters:
5258
- stubs/Symfony/Component/HttpFoundation/Session.stub
5359
- stubs/Symfony/Component/Messenger/StampInterface.stub
5460
- stubs/Symfony/Component/Messenger/Envelope.stub
61+
- stubs/Symfony/Component/OptionsResolver/Exception/InvalidOptionsException.stub
5562
- stubs/Symfony/Component/OptionsResolver/Options.stub
5663
- stubs/Symfony/Component/Process/Process.stub
5764
- stubs/Symfony/Component/PropertyAccess/PropertyPathInterface.stub
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Symfony\Component\Form;
4+
5+
/**
6+
* @template TData
7+
*
8+
* @implements FormTypeInterface<TData>
9+
*/
10+
abstract class AbstractType implements FormTypeInterface
11+
{
12+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace Symfony\Component\Form;
4+
5+
use Symfony\Component\Form\Extension\Core\Type\FormType;
6+
7+
interface FormFactoryInterface
8+
{
9+
/**
10+
* @template TFormType of FormTypeInterface<TData>
11+
* @template TData
12+
*
13+
* @param class-string<TFormType> $type
14+
* @param TData $data
15+
* @param array<string, mixed> $options
16+
*
17+
* @phpstan-return ($data is null ? FormInterface<null|TData> : FormInterface<TData>)
18+
*
19+
* @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
20+
*/
21+
public function create(string $type = FormType::class, $data = null, array $options = []): FormInterface;
22+
23+
/**
24+
* @template TFormType of FormTypeInterface<TData>
25+
* @template TData
26+
*
27+
* @param class-string<TFormType> $type
28+
* @param TData $data
29+
* @param array<string, mixed> $options
30+
*
31+
* @phpstan-return ($data is null ? FormInterface<null|TData> : FormInterface<TData>)
32+
*
33+
* @throws \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
34+
*/
35+
public function createNamed(string $name, string $type = FormType::class, $data = null, array $options = []): FormInterface;
36+
}

‎stubs/Symfony/Component/Form/FormInterface.stub‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,22 @@
33
namespace Symfony\Component\Form;
44

55
/**
6-
* @extends \ArrayAccess<string, \Symfony\Component\Form\FormInterface>
7-
* @extends \Traversable<string, \Symfony\Component\Form\FormInterface>
6+
* @template TData
7+
*
8+
* @extends \ArrayAccess<string, \Symfony\Component\Form\FormInterface<mixed>>
9+
* @extends \Traversable<string, \Symfony\Component\Form\FormInterface<mixed>>
810
*/
911
interface FormInterface extends \ArrayAccess, \Traversable, \Countable
1012
{
13+
/**
14+
* @param TData $modelData
15+
*
16+
* @return $this
17+
*/
18+
public function setData($modelData): FormInterface;
1119

20+
/**
21+
* @return TData
22+
*/
23+
public function getData();
1224
}

‎stubs/Symfony/Component/Form/FormTypeExtensionInterface.stub‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace Symfony\Component\Form;
44

5+
/**
6+
* @template TData
7+
*/
58
interface FormTypeExtensionInterface
69
{
710
/**
@@ -10,11 +13,13 @@ interface FormTypeExtensionInterface
1013
public function buildForm(FormBuilderInterface $builder, array $options): void;
1114

1215
/**
16+
* @phpstan-param FormInterface<TData> $form
1317
* @param array<string, mixed> $options
1418
*/
1519
public function buildView(FormView $view, FormInterface $form, array $options): void;
1620

1721
/**
22+
* @phpstan-param FormInterface<TData> $form
1823
* @param array<string, mixed> $options
1924
*/
2025
public function finishView(FormView $view, FormInterface $form, array $options): void;

‎stubs/Symfony/Component/Form/FormTypeInterface.stub‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace Symfony\Component\Form;
44

5+
/**
6+
* @template TData
7+
*/
58
interface FormTypeInterface
69
{
710
/**
@@ -10,11 +13,13 @@ interface FormTypeInterface
1013
public function buildForm(FormBuilderInterface $builder, array $options): void;
1114

1215
/**
16+
* @phpstan-param FormInterface<TData> $form
1317
* @param array<string, mixed> $options
1418
*/
1519
public function buildView(FormView $view, FormInterface $form, array $options): void;
1620

1721
/**
22+
* @phpstan-param FormInterface<TData> $form
1823
* @param array<string, mixed> $options
1924
*/
2025
public function finishView(FormView $view, FormInterface $form, array $options): void;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Symfony\Component\OptionsResolver\Exception;
4+
5+
class InvalidOptionsException extends \InvalidArgumentException
6+
{
7+
}

‎tests/Type/Symfony/ExtensionTest.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public function dataFileAsserts(): iterable
5656

5757
yield from $this->gatherAssertTypes(__DIR__ . '/data/FormInterface_getErrors.php');
5858
yield from $this->gatherAssertTypes(__DIR__ . '/data/cache.php');
59+
yield from $this->gatherAssertTypes(__DIR__ . '/data/form_data_type.php');
5960
}
6061

6162
/**
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace GenericFormDataType;
4+
5+
use Symfony\Component\Form\AbstractType;
6+
use Symfony\Component\Form\Extension\Core\Type\NumberType;
7+
use Symfony\Component\Form\Extension\Core\Type\TextType;
8+
use Symfony\Component\Form\FormBuilderInterface;
9+
use Symfony\Component\Form\FormFactoryInterface;
10+
use Symfony\Component\OptionsResolver\OptionsResolver;
11+
use function PHPStan\Testing\assertType;
12+
13+
class DataClass
14+
{
15+
16+
/** @var int */
17+
public $foo;
18+
19+
/** @var string */
20+
public $bar;
21+
22+
}
23+
24+
/**
25+
* @extends AbstractType<DataClass>
26+
*/
27+
class DataClassType extends AbstractType
28+
{
29+
30+
public function buildForm(FormBuilderInterface $builder, array $options): void
31+
{
32+
$builder
33+
->add('foo', NumberType::class)
34+
->add('bar', TextType::class)
35+
;
36+
}
37+
38+
public function configureOptions(OptionsResolver $resolver): void
39+
{
40+
$resolver
41+
->setDefaults([
42+
'data_class' => DataClass::class,
43+
])
44+
;
45+
}
46+
47+
}
48+
49+
class FormFactoryAwareClass
50+
{
51+
52+
/** @var FormFactoryInterface */
53+
private $formFactory;
54+
55+
public function __construct(FormFactoryInterface $formFactory)
56+
{
57+
$this->formFactory = $formFactory;
58+
}
59+
60+
public function doSomething(): void
61+
{
62+
$form = $this->formFactory->create(DataClassType::class, new DataClass());
63+
assertType('GenericFormDataType\DataClass', $form->getData());
64+
}
65+
66+
public function doSomethingNullable(): void
67+
{
68+
$form = $this->formFactory->create(DataClassType::class);
69+
assertType('GenericFormDataType\DataClass|null', $form->getData());
70+
}
71+
72+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /