Skip to content

Commit 91297ea

Browse files
Merge branch '7.4' into 8.0
* 7.4: [Messenger] Allow to use custom http client for sqs messenger transport [JsonStreamer] Merge `PropertyMetadata` value transformers [Mailer] Relax regexp to parse message ids [Mailer] Fix parsing message ids in SMTP responses Reviewed translations [HttpClient] Consider cached responses without expiration as immediately stale [Routing] Indicate type of rejected object in CompiledUrlMatcherDumper [Workflow] Extract code from the data collector to a dedicated class [Messenger] Add `MessageSentToTransportsEvent` Add FormFlow for multistep forms management [HttpKernel][DebugBundle] Collect dumps when console profiling is enabled
2 parents 8535417 + 4a374b6 commit 91297ea

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+3534
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ CHANGELOG
1515
* Add `input=date_point` to `DateTimeType`, `DateType` and `TimeType`
1616
* Add support for guessing form type of enum properties
1717
* Add `active_at`, `not_active_at` and `legal_tender` options to `CurrencyType`
18+
* Add `FormFlow` for multistep forms management
1819

1920
7.3
2021
---

Extension/Core/CoreExtension.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory;
1818
use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator;
1919
use Symfony\Component\Form\Extension\Core\Type\TransformationFailureExtension;
20+
use Symfony\Component\Form\Flow;
2021
use Symfony\Component\PropertyAccess\PropertyAccess;
2122
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
2223
use Symfony\Contracts\Translation\TranslatorInterface;
@@ -78,6 +79,12 @@ protected function loadTypes(): array
7879
new Type\TelType(),
7980
new Type\ColorType($this->translator),
8081
new Type\WeekType(),
82+
new Flow\Type\ButtonFlowType(),
83+
new Flow\Type\FinishFlowType(),
84+
new Flow\Type\NavigatorFlowType(),
85+
new Flow\Type\NextFlowType(),
86+
new Flow\Type\PreviousFlowType(),
87+
new Flow\Type\FormFlowType($this->propertyAccessor),
8188
];
8289
}
8390

Extension/HttpFoundation/HttpFoundationExtension.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ protected function loadTypeExtensions(): array
2424
{
2525
return [
2626
new Type\FormTypeHttpFoundationExtension(),
27+
new Type\FormFlowTypeSessionDataStorageExtension(),
2728
];
2829
}
2930
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Extension\HttpFoundation\Type;
13+
14+
use Symfony\Component\Form\AbstractTypeExtension;
15+
use Symfony\Component\Form\Flow\DataStorage\SessionDataStorage;
16+
use Symfony\Component\Form\Flow\FormFlowBuilderInterface;
17+
use Symfony\Component\Form\Flow\Type\FormFlowType;
18+
use Symfony\Component\Form\FormBuilderInterface;
19+
use Symfony\Component\HttpFoundation\RequestStack;
20+
21+
class FormFlowTypeSessionDataStorageExtension extends AbstractTypeExtension
22+
{
23+
public function __construct(
24+
private readonly ?RequestStack $requestStack = null,
25+
) {
26+
}
27+
28+
public function buildForm(FormBuilderInterface $builder, array $options): void
29+
{
30+
if (!$builder instanceof FormFlowBuilderInterface) {
31+
throw new \InvalidArgumentException(\sprintf('The "%s" can only be used with FormFlowType.', self::class));
32+
}
33+
34+
if (null === $this->requestStack || null !== $options['data_storage']) {
35+
return;
36+
}
37+
38+
$key = \sprintf('_sf_formflow.%s_%s', strtolower(str_replace('\\', '_', $builder->getType()->getInnerType()::class)), $builder->getName());
39+
$builder->setDataStorage(new SessionDataStorage($key, $this->requestStack));
40+
}
41+
42+
public static function getExtendedTypes(): iterable
43+
{
44+
return [FormFlowType::class];
45+
}
46+
}

Flow/AbstractButtonFlowType.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Flow;
13+
14+
use Symfony\Component\Form\AbstractType;
15+
use Symfony\Component\Form\Flow\Type\ButtonFlowType;
16+
17+
/**
18+
* @author Yonel Ceruto <[email protected]>
19+
*/
20+
abstract class AbstractButtonFlowType extends AbstractType implements ButtonFlowTypeInterface
21+
{
22+
public function getParent(): string
23+
{
24+
return ButtonFlowType::class;
25+
}
26+
}

Flow/AbstractFlowType.php

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Flow;
13+
14+
use Symfony\Component\Form\AbstractType;
15+
use Symfony\Component\Form\Flow\Type\FormFlowType;
16+
use Symfony\Component\Form\FormBuilderInterface;
17+
use Symfony\Component\Form\FormInterface;
18+
use Symfony\Component\Form\FormView;
19+
20+
/**
21+
* @author Yonel Ceruto <[email protected]>
22+
*/
23+
abstract class AbstractFlowType extends AbstractType implements FormFlowTypeInterface
24+
{
25+
final public function buildForm(FormBuilderInterface $builder, array $options): void
26+
{
27+
if (!$builder instanceof FormFlowBuilderInterface) {
28+
throw new \InvalidArgumentException(\sprintf('The "%s" can only be used with FormFlowType.', self::class));
29+
}
30+
31+
$this->buildFormFlow($builder, $options);
32+
}
33+
34+
final public function buildView(FormView $view, FormInterface $form, array $options): void
35+
{
36+
if (!$form instanceof FormFlowInterface) {
37+
throw new \InvalidArgumentException(\sprintf('The "%s" can only be used with FormFlowType.', self::class));
38+
}
39+
40+
$this->buildViewFlow($view, $form, $options);
41+
}
42+
43+
final public function finishView(FormView $view, FormInterface $form, array $options): void
44+
{
45+
if (!$form instanceof FormFlowInterface) {
46+
throw new \InvalidArgumentException(\sprintf('The "%s" can only be used with FormFlowType.', self::class));
47+
}
48+
49+
$this->finishViewFlow($view, $form, $options);
50+
}
51+
52+
public function buildFormFlow(FormFlowBuilderInterface $builder, array $options): void
53+
{
54+
}
55+
56+
public function buildViewFlow(FormView $view, FormFlowInterface $form, array $options): void
57+
{
58+
}
59+
60+
public function finishViewFlow(FormView $view, FormFlowInterface $form, array $options): void
61+
{
62+
}
63+
64+
public function getParent(): string
65+
{
66+
return FormFlowType::class;
67+
}
68+
}

Flow/ButtonFlow.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Flow;
13+
14+
use Symfony\Component\Form\FormInterface;
15+
use Symfony\Component\Form\SubmitButton;
16+
17+
/**
18+
* A button that submits the form and handles an action.
19+
*
20+
* @author Yonel Ceruto <[email protected]>
21+
*/
22+
class ButtonFlow extends SubmitButton implements ButtonFlowInterface
23+
{
24+
private mixed $data = null;
25+
private bool $handled = false;
26+
27+
public function submit(array|string|null $submittedData, bool $clearMissing = true): static
28+
{
29+
if ($this->isSubmitted()) {
30+
return $this; // ignore double submit
31+
}
32+
33+
parent::submit($submittedData, $clearMissing);
34+
35+
if ($this->isSubmitted()) {
36+
$this->data = $submittedData;
37+
}
38+
39+
return $this;
40+
}
41+
42+
public function getViewData(): mixed
43+
{
44+
return $this->data;
45+
}
46+
47+
public function handle(): void
48+
{
49+
/** @var FormInterface $form */
50+
$form = $this->getParent();
51+
$data = $form->getData();
52+
53+
while ($form && !$form instanceof FormFlowInterface) {
54+
$form = $form->getParent();
55+
}
56+
57+
$handler = $this->getConfig()->getOption('handler');
58+
$handler($data, $this, $form);
59+
60+
$this->handled = true;
61+
}
62+
63+
public function isHandled(): bool
64+
{
65+
return $this->handled;
66+
}
67+
68+
public function isResetAction(): bool
69+
{
70+
return 'reset' === $this->getConfig()->getAttribute('action');
71+
}
72+
73+
public function isPreviousAction(): bool
74+
{
75+
return 'previous' === $this->getConfig()->getAttribute('action');
76+
}
77+
78+
public function isNextAction(): bool
79+
{
80+
return 'next' === $this->getConfig()->getAttribute('action');
81+
}
82+
83+
public function isFinishAction(): bool
84+
{
85+
return 'finish' === $this->getConfig()->getAttribute('action');
86+
}
87+
88+
public function isClearSubmission(): bool
89+
{
90+
return $this->getConfig()->getOption('clear_submission');
91+
}
92+
}

Flow/ButtonFlowBuilder.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Flow;
13+
14+
use Symfony\Component\Form\ButtonBuilder;
15+
16+
/**
17+
* A builder for {@link ButtonFlow} instances.
18+
*
19+
* @author Yonel Ceruto <[email protected]>
20+
*/
21+
class ButtonFlowBuilder extends ButtonBuilder
22+
{
23+
public function getForm(): ButtonFlow
24+
{
25+
return new ButtonFlow($this->getFormConfig());
26+
}
27+
}

Flow/ButtonFlowInterface.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Flow;
13+
14+
use Symfony\Component\Form\ClickableInterface;
15+
use Symfony\Component\Form\FormInterface;
16+
17+
/**
18+
* @author Yonel Ceruto <[email protected]>
19+
*/
20+
interface ButtonFlowInterface extends FormInterface, ClickableInterface
21+
{
22+
/**
23+
* Executes the callable handler.
24+
*/
25+
public function handle(): void;
26+
27+
/**
28+
* Checks if the callable handler was already called.
29+
*/
30+
public function isHandled(): bool;
31+
32+
/**
33+
* Checks if the button's action is 'reset'.
34+
*/
35+
public function isResetAction(): bool;
36+
37+
/**
38+
* Checks if the button's action is 'previous'.
39+
*/
40+
public function isPreviousAction(): bool;
41+
42+
/**
43+
* Checks if the button's action is 'next'.
44+
*/
45+
public function isNextAction(): bool;
46+
47+
/**
48+
* Checks if the button's action is 'finish'.
49+
*/
50+
public function isFinishAction(): bool;
51+
52+
/**
53+
* Checks if the button is configured to clear submission data.
54+
*/
55+
public function isClearSubmission(): bool;
56+
}

Flow/ButtonFlowTypeInterface.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Flow;
13+
14+
use Symfony\Component\Form\FormTypeInterface;
15+
16+
/**
17+
* A type that should be converted into a {@link ButtonFlow} instance.
18+
*
19+
* @author Yonel Ceruto <[email protected]>
20+
*/
21+
interface ButtonFlowTypeInterface extends FormTypeInterface
22+
{
23+
}

0 commit comments

Comments
 (0)