/
githubmirror
/
symfony
Обзор
Документация
Войти
/
githubmirror
/
symfony
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
8.2
src/Symfony/Component/Form/Tests/Flow/FormFlowTest.php
973 строки
36 KB
Dariusz Ruminski
PHP CS Fixer: enable static_lambda for Form
28 дек 2025, 19:33
28 дек 2025, 19:33
9db5fa0
Код
Авторство
О чём код?
<?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\Form\Tests\Flow; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\BadMethodCallException; use Symfony\Component\Form\Exception\RuntimeException; use Symfony\Component\Form\Extension\Validator\ValidatorExtension; use Symfony\Component\Form\Flow\ButtonFlowInterface; use Symfony\Component\Form\Flow\DataStorage\InMemoryDataStorage; use Symfony\Component\Form\Flow\FormFlowCursor; use Symfony\Component\Form\Flow\FormFlowInterface; use Symfony\Component\Form\Flow\Type\NextFlowType; use Symfony\Component\Form\Flow\Type\PreviousFlowType; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\Forms; use Symfony\Component\Form\Tests\Fixtures\Flow\Data\UserSignUp; use Symfony\Component\Form\Tests\Fixtures\Flow\Extension\UserSignUpTypeExtension; use Symfony\Component\Form\Tests\Fixtures\Flow\LastStepSkippedType; use Symfony\Component\Form\Tests\Fixtures\Flow\UserSignUpType; use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory; use Symfony\Component\Validator\Mapping\Loader\AttributeLoader; use Symfony\Component\Validator\Validation; class FormFlowTest extends TestCase { private FormFactoryInterface $factory; protected function setUp(): void { $validator = Validation::createValidatorBuilder() ->setMetadataFactory(new LazyLoadingMetadataFactory(new AttributeLoader())) ->getValidator(); $this->factory = Forms::createFormFactoryBuilder() ->addExtensions([new ValidatorExtension($validator)]) ->getFormFactory(); } public function testFlowConfig() { $flow = $this->factory->create(UserSignUpType::class, new UserSignUp()); $config = $flow->getConfig(); self::assertInstanceOf(UserSignUp::class, $data = $config->getData()); self::assertEquals(['data' => $data], $config->getInitialOptions()); self::assertCount(3, $config->getSteps()); self::assertTrue($config->hasStep('personal')); self::assertTrue($config->hasStep('professional')); self::assertTrue($config->hasStep('account')); } public function testFlowCursor() { $flow = $this->factory->create(UserSignUpType::class, new UserSignUp()); $cursor = $flow->getCursor(); self::assertSame('personal', $cursor->getCurrentStep()); self::assertTrue($cursor->isFirstStep()); self::assertFalse($cursor->isLastStep()); self::assertSame('personal', $cursor->getFirstStep()); self::assertNull($cursor->getPreviousStep()); self::assertSame('professional', $cursor->getNextStep()); self::assertSame('account', $cursor->getLastStep()); self::assertSame(['personal', 'professional', 'account'], $cursor->getSteps()); self::assertSame(0, $cursor->getStepIndex()); self::assertSame(3, $cursor->getTotalSteps()); self::assertFalse($cursor->canMoveBack()); self::assertTrue($cursor->canMoveNext()); $cursor = $cursor->withCurrentStep('professional'); self::assertSame('professional', $cursor->getCurrentStep()); self::assertFalse($cursor->isFirstStep()); self::assertFalse($cursor->isLastStep()); self::assertSame('personal', $cursor->getFirstStep()); self::assertSame('personal', $cursor->getPreviousStep()); self::assertSame('account', $cursor->getNextStep()); self::assertSame('account', $cursor->getLastStep()); self::assertSame(1, $cursor->getStepIndex()); self::assertSame(3, $cursor->getTotalSteps()); self::assertTrue($cursor->canMoveBack()); self::assertTrue($cursor->canMoveNext()); $cursor = $cursor->withCurrentStep('account'); self::assertSame('account', $cursor->getCurrentStep()); self::assertFalse($cursor->isFirstStep()); self::assertTrue($cursor->isLastStep()); self::assertSame('personal', $cursor->getFirstStep()); self::assertSame('professional', $cursor->getPreviousStep()); self::assertNull($cursor->getNextStep()); self::assertSame('account', $cursor->getLastStep()); self::assertSame(2, $cursor->getStepIndex()); self::assertSame(3, $cursor->getTotalSteps()); self::assertTrue($cursor->canMoveBack()); self::assertFalse($cursor->canMoveNext()); } public function testFlowViewVars() { $view = $this->factory->create(UserSignUpType::class, new UserSignUp()) ->createView(); self::assertArrayHasKey('steps', $view->vars); self::assertArrayHasKey('visible_steps', $view->vars); self::assertCount(3, $view->vars['steps']); self::assertCount(2, $view->vars['visible_steps']); self::assertArrayHasKey('personal', $view->vars['steps']); self::assertArrayHasKey('professional', $view->vars['steps']); self::assertArrayHasKey('account', $view->vars['steps']); self::assertArrayHasKey('personal', $view->vars['visible_steps']); self::assertArrayHasKey('account', $view->vars['visible_steps']); $step1 = [ 'name' => 'personal', 'index' => 0, 'position' => 1, 'is_current_step' => true, 'can_be_skipped' => false, 'is_skipped' => false, ]; $step2 = [ 'name' => 'professional', 'index' => 1, 'position' => -1, 'is_current_step' => false, 'can_be_skipped' => true, 'is_skipped' => true, ]; $step3 = [ 'name' => 'account', 'index' => 2, 'position' => 2, 'is_current_step' => false, 'can_be_skipped' => false, 'is_skipped' => false, ]; self::assertSame($step1, $view->vars['steps']['personal']); self::assertSame($step2, $view->vars['steps']['professional']); self::assertSame($step3, $view->vars['steps']['account']); self::assertSame($step1, $view->vars['visible_steps']['personal']); self::assertSame($step3, $view->vars['visible_steps']['account']); } public function testWholeStepsFlow() { $data = new UserSignUp(); $flow = $this->factory->create(UserSignUpType::class, $data); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); self::assertFalse($flow->isSubmitted()); self::assertNull($flow->getClickedButton()); self::assertTrue($flow->has('personal')); self::assertTrue($flow->has('navigator')); $stepForm = $flow->get('personal'); self::assertCount(3, $stepForm->all()); self::assertTrue($stepForm->has('firstName')); self::assertTrue($stepForm->has('lastName')); self::assertTrue($stepForm->has('worker')); $navigatorForm = $flow->get('navigator'); self::assertCount(2, $navigatorForm->all()); self::assertTrue($navigatorForm->has('reset')); self::assertTrue($navigatorForm->has('next')); $flow->submit([ 'personal' => [ 'firstName' => 'John', 'lastName' => 'Doe', 'worker' => '1', ], 'navigator' => [ 'next' => '', ], ]); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertFalse($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isNextAction()); self::assertTrue($button->isClicked()); $flow = $flow->getStepForm(); self::assertSame('professional', $data->currentStep); self::assertSame('professional', $flow->getCursor()->getCurrentStep()); self::assertFalse($flow->isSubmitted()); self::assertNull($flow->getClickedButton()); self::assertTrue($flow->has('professional')); self::assertTrue($flow->has('navigator')); $stepForm = $flow->get('professional'); self::assertCount(2, $stepForm->all()); self::assertTrue($stepForm->has('company')); self::assertTrue($stepForm->has('role')); $navigatorForm = $flow->get('navigator'); self::assertCount(4, $navigatorForm->all()); self::assertTrue($navigatorForm->has('reset')); self::assertTrue($navigatorForm->has('previous')); self::assertTrue($navigatorForm->has('skip')); self::assertTrue($navigatorForm->has('next')); $flow->submit([ 'professional' => [ 'company' => 'Acme', 'role' => 'ROLE_DEVELOPER', ], 'navigator' => [ 'next' => '', ], ]); self::assertSame('professional', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertFalse($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isNextAction()); self::assertTrue($button->isClicked()); $flow = $flow->getStepForm(); /** @var UserSignUp $data */ $data = $flow->getViewData(); self::assertSame('account', $data->currentStep); self::assertSame('account', $flow->getCursor()->getCurrentStep()); self::assertFalse($flow->isSubmitted()); self::assertNull($flow->getClickedButton()); self::assertTrue($flow->has('account')); self::assertTrue($flow->has('navigator')); $stepForm = $flow->get('account'); self::assertCount(2, $stepForm->all()); self::assertTrue($stepForm->has('email')); self::assertTrue($stepForm->has('password')); $navigatorForm = $flow->get('navigator'); self::assertCount(3, $navigatorForm->all()); self::assertTrue($navigatorForm->has('reset')); self::assertTrue($navigatorForm->has('previous')); self::assertTrue($navigatorForm->has('finish')); $flow->submit([ 'account' => [ 'email' => 'john@acme.com', 'password' => 'eBvU2vBLfSXqf36', ], 'navigator' => [ 'finish' => '', ], ]); self::assertSame('account', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertTrue($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isFinishAction()); self::assertTrue($button->isClicked()); self::assertSame($data, $flow->getViewData()); self::assertSame('John', $data->firstName); self::assertSame('Doe', $data->lastName); self::assertTrue($data->worker); self::assertSame('Acme', $data->company); self::assertSame('ROLE_DEVELOPER', $data->role); self::assertSame('john@acme.com', $data->email); self::assertSame('eBvU2vBLfSXqf36', $data->password); } public function testPreviousActionWithPurgeSubmission() { $data = new UserSignUp(); $data->firstName = 'John'; $data->lastName = 'Doe'; $data->worker = true; $data->currentStep = 'professional'; $flow = $this->factory->create(UserSignUpType::class, $data); self::assertSame('professional', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('professional')); $flow->submit([ 'professional' => [ 'company' => 'Acme', 'role' => 'ROLE_DEVELOPER', ], 'navigator' => [ 'previous' => '', ], ]); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertFalse($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isPreviousAction()); $flow = $flow->getStepForm(); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('personal'), 'back action should move the flow one step back'); self::assertNull($data->company, 'pro step should be silenced on submit'); self::assertNull($data->role, 'pro step should be silenced on submit'); } public function testPreviousActionWithoutPurgeSubmission() { $data = new UserSignUp(); $data->firstName = 'John'; $data->lastName = 'Doe'; $data->worker = true; $data->currentStep = 'professional'; $flow = $this->factory->create(UserSignUpType::class, $data); // previous action without purge submission $flow->get('navigator')->add('previous', PreviousFlowType::class, [ 'validate' => false, 'validation_groups' => false, 'clear_submission' => false, 'include_if' => static fn (FormFlowCursor $cursor) => $cursor->canMoveBack(), ]); self::assertSame('professional', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('professional')); $flow->submit([ 'professional' => [ 'company' => 'Acme', 'role' => 'ROLE_DEVELOPER', ], 'navigator' => [ 'previous' => '', ], ]); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertFalse($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isPreviousAction()); $flow = $flow->getStepForm(); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('personal'), 'previous action should move the flow one step back'); self::assertSame('Acme', $data->company, 'pro step should NOT be silenced on submit'); self::assertSame('ROLE_DEVELOPER', $data->role, 'pro step should NOT be silenced on submit'); } public function testSkipStepBasedOnData() { $flow = $this->factory->create(UserSignUpType::class, new UserSignUp()); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('personal')); $flow->submit([ 'personal' => [ 'firstName' => 'John', 'lastName' => 'Doe', // worker checkbox was not clicked ], 'navigator' => [ 'next' => '', ], ]); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertFalse($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isNextAction()); $flow = $flow->getStepForm(); self::assertFalse($flow->has('professional'), 'pro step should be skipped'); self::assertSame('account', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('account')); } public function testResetAction() { $data = new UserSignUp(); $data->firstName = 'John'; $data->lastName = 'Doe'; $data->worker = true; $data->currentStep = 'professional'; $dataStorage = new InMemoryDataStorage('user_sign_up'); $dataStorage->save($data); $flow = $this->factory->create(UserSignUpType::class, new UserSignUp(), [ 'data_storage' => $dataStorage, ]); self::assertSame('professional', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('professional')); $flow->submit([ 'professional' => [ 'company' => 'Acme', 'role' => 'ROLE_DEVELOPER', ], 'navigator' => [ 'reset' => '', ], ]); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertFalse($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isResetAction()); $flow = $flow->getStepForm(); /** @var UserSignUp $data */ $data = $flow->getViewData(); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('personal'), 'reset action should move the flow to the initial step'); self::assertNull($data->firstName); self::assertNull($data->lastName); self::assertFalse($data->worker); self::assertNull($data->company); self::assertNull($data->role); } public function testResetManually() { $data = new UserSignUp(); $data->firstName = 'John'; $data->lastName = 'Doe'; $data->worker = true; $data->currentStep = 'professional'; $dataStorage = new InMemoryDataStorage('user_sign_up'); $dataStorage->save($data); $flow = $this->factory->create(UserSignUpType::class, new UserSignUp(), [ 'data_storage' => $dataStorage, ]); self::assertSame('professional', $flow->getCursor()->getCurrentStep()); $flow->reset(); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); } public function testSkipAction() { $data = new UserSignUp(); $data->firstName = 'John'; $data->lastName = 'Doe'; $data->worker = true; $data->currentStep = 'professional'; $dataStorage = new InMemoryDataStorage('user_sign_up'); $dataStorage->save($data); $flow = $this->factory->create(UserSignUpType::class, new UserSignUp(), [ 'data_storage' => $dataStorage, ]); self::assertSame('professional', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('professional')); $flow->submit([ 'professional' => [ 'company' => 'Acme', 'role' => 'ROLE_DEVELOPER', ], 'navigator' => [ 'skip' => '', ], ]); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertFalse($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isNextAction()); self::assertSame('skip', $button->getName()); $flow = $flow->getStepForm(); /** @var UserSignUp $data */ $data = $flow->getViewData(); self::assertSame('account', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('account'), 'skip action should move the flow to the next step but skip submitted data and clear'); self::assertSame('John', $data->firstName); self::assertSame('Doe', $data->lastName); self::assertTrue($data->worker); self::assertNull($data->company); self::assertNull($data->role); } public function testTypeExtensionAndStepsPriority() { $factory = Forms::createFormFactoryBuilder() ->addTypeExtension(new UserSignUpTypeExtension()) ->getFormFactory(); $flow = $factory->create(UserSignUpType::class, new UserSignUp()); self::assertSame('first', $flow->getCursor()->getCurrentStep()); self::assertSame(['first', 'personal', 'professional', 'account', 'last'], $flow->getCursor()->getSteps()); } public function testMoveBackToStep() { $data = new UserSignUp(); $data->firstName = 'John'; $data->lastName = 'Doe'; $data->worker = true; $data->company = 'Acme'; $data->role = 'ROLE_DEVELOPER'; $data->currentStep = 'account'; $flow = $this->factory->create(UserSignUpType::class, $data); $flow->get('navigator')->add('back_to_step', PreviousFlowType::class, [ 'validate' => false, 'validation_groups' => false, 'clear_submission' => false, ]); self::assertSame('account', $flow->getCursor()->getCurrentStep()); $flow->submit([ 'account' => [ 'email' => 'jdoe@acme.com', 'password' => '$ecret', ], 'navigator' => [ 'back_to_step' => 'personal', ], ]); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertFalse($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isPreviousAction()); self::assertSame('personal', $button->getViewData()); $flow = $flow->getStepForm(); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('personal')); self::assertSame('John', $data->firstName); self::assertSame('Acme', $data->company); self::assertSame('jdoe@acme.com', $data->email); } public function testMoveManually() { $data = new UserSignUp(); $data->firstName = 'John'; $data->lastName = 'Doe'; $data->worker = true; $data->currentStep = 'professional'; $dataStorage = new InMemoryDataStorage('user_sign_up'); $dataStorage->save($data); $flow = $this->factory->create(UserSignUpType::class, new UserSignUp(), [ 'data_storage' => $dataStorage, ]); self::assertSame('professional', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('professional')); $flow->movePrevious(); $flow = $flow->newStepForm(); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('personal')); $flow->moveNext(); $flow = $flow->newStepForm(); self::assertSame('professional', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('professional')); } public function testInvalidMovePreviousUntilAheadStep() { $data = new UserSignUp(); $data->currentStep = 'personal'; $flow = $this->factory->create(UserSignUpType::class, $data); $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Cannot move back to step "account" because it is ahead of the current step "personal".'); $flow->movePrevious('account'); } public function testInvalidMovePreviousUntilSkippedStep() { $data = new UserSignUp(); $data->worker = false; $data->currentStep = 'account'; $flow = $this->factory->create(UserSignUpType::class, $data); $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Cannot move back to step "professional" because it is a skipped step.'); $flow->movePrevious('professional'); } public function testInvalidStepForm() { $flow = $this->factory->create(UserSignUpType::class, new UserSignUp()); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('personal')); $flow->submit([ 'personal' => [ 'firstName' => '', // This value should not be blank 'lastName' => 'Doe', ], 'navigator' => [ 'next' => '', ], ]); self::assertTrue($flow->isSubmitted()); self::assertFalse($flow->isValid()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isNextAction()); self::assertSame($flow, $flow->getStepForm()); self::assertSame('This value should not be blank.', $flow->getErrors(true)->current()->getMessage()); } public function testCannotModifyStepConfigAfterFormBuilding() { $flow = $this->factory->create(UserSignUpType::class, new UserSignUp()); $this->expectException(BadMethodCallException::class); $this->expectExceptionMessage('StepFlowBuilder methods cannot be accessed anymore once the builder is turned into a StepFlowConfigInterface instance.'); $flow->getConfig()->getStep('personal')->setPriority(0); } public function testIgnoreSubmissionIfStepIsMissing() { $flow = $this->factory->create(UserSignUpType::class, new UserSignUp()); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->has('personal')); $flow->submit([ 'account' => [ 'firstName' => '', 'lastName' => '', ], 'navigator' => [ 'previous' => '', ], ]); self::assertFalse($flow->isSubmitted()); } public function testViewVars() { $flow = $this->factory->create(UserSignUpType::class, new UserSignUp()); $view = $flow->createView(); self::assertInstanceOf(FormFlowCursor::class, $view->vars['cursor']); self::assertCount(3, $view->vars['steps']); self::assertSame(['personal', 'professional', 'account'], array_keys($view->vars['steps'])); self::assertSame('personal', $view->vars['steps']['personal']['name']); self::assertTrue($view->vars['steps']['personal']['is_current_step']); self::assertFalse($view->vars['steps']['personal']['is_skipped']); self::assertSame('professional', $view->vars['steps']['professional']['name']); self::assertFalse($view->vars['steps']['professional']['is_current_step']); self::assertTrue($view->vars['steps']['professional']['is_skipped']); self::assertSame('account', $view->vars['steps']['account']['name']); self::assertFalse($view->vars['steps']['account']['is_current_step']); self::assertFalse($view->vars['steps']['account']['is_skipped']); } public function testFallbackCurrentStep() { $flow = $this->factory->create(UserSignUpType::class, new UserSignUp()); /** @var UserSignUp $data */ $data = $flow->getViewData(); self::assertSame('personal', $flow->getCursor()->getCurrentStep(), 'The current step should be the first one depending on the step priority'); self::assertSame('personal', $data->currentStep); } public function testInitialCurrentStep() { $data = new UserSignUp(); $data->currentStep = 'professional'; $flow = $this->factory->create(UserSignUpType::class, $data); self::assertSame('professional', $flow->getCursor()->getCurrentStep(), 'The current step should be the one set in the initial data'); self::assertSame('professional', $data->currentStep); } public function testFormFlowWithArrayData() { $flow = $this->factory->create(UserSignUpType::class, [], [ 'data_class' => null, 'step_property_path' => '[currentStep]', ]); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); self::assertFalse($flow->isSubmitted()); self::assertNull($flow->getClickedButton()); self::assertTrue($flow->has('personal')); self::assertTrue($flow->has('navigator')); $stepForm = $flow->get('personal'); self::assertCount(3, $stepForm->all()); self::assertTrue($stepForm->has('firstName')); self::assertTrue($stepForm->has('lastName')); self::assertTrue($stepForm->has('worker')); $navigatorForm = $flow->get('navigator'); self::assertCount(2, $navigatorForm->all()); self::assertTrue($navigatorForm->has('reset')); self::assertTrue($navigatorForm->has('next')); $flow->submit([ 'personal' => [ 'firstName' => 'John', 'lastName' => 'Doe', 'worker' => '1', ], 'navigator' => [ 'next' => '', ], ]); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertFalse($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isNextAction()); self::assertTrue($button->isClicked()); $flow = $flow->getStepForm(); $data = $flow->getData(); self::assertSame('professional', $data['currentStep']); self::assertSame('professional', $flow->getCursor()->getCurrentStep()); self::assertFalse($flow->isSubmitted()); self::assertNull($flow->getClickedButton()); self::assertTrue($flow->has('professional')); self::assertTrue($flow->has('navigator')); $stepForm = $flow->get('professional'); self::assertCount(2, $stepForm->all()); self::assertTrue($stepForm->has('company')); self::assertTrue($stepForm->has('role')); $navigatorForm = $flow->get('navigator'); self::assertCount(4, $navigatorForm->all()); self::assertTrue($navigatorForm->has('reset')); self::assertTrue($navigatorForm->has('previous')); self::assertTrue($navigatorForm->has('skip')); self::assertTrue($navigatorForm->has('next')); $flow->submit([ 'professional' => [ 'company' => 'Acme', 'role' => 'ROLE_DEVELOPER', ], 'navigator' => [ 'next' => '', ], ]); self::assertSame('professional', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertFalse($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isNextAction()); self::assertTrue($button->isClicked()); $flow = $flow->getStepForm(); $data = $flow->getData(); self::assertSame('account', $data['currentStep']); self::assertSame('account', $flow->getCursor()->getCurrentStep()); self::assertFalse($flow->isSubmitted()); self::assertNull($flow->getClickedButton()); self::assertTrue($flow->has('account')); self::assertTrue($flow->has('navigator')); $stepForm = $flow->get('account'); self::assertCount(2, $stepForm->all()); self::assertTrue($stepForm->has('email')); self::assertTrue($stepForm->has('password')); $navigatorForm = $flow->get('navigator'); self::assertCount(3, $navigatorForm->all()); self::assertTrue($navigatorForm->has('reset')); self::assertTrue($navigatorForm->has('previous')); self::assertTrue($navigatorForm->has('finish')); $flow->submit([ 'account' => [ 'email' => 'john@acme.com', 'password' => 'eBvU2vBLfSXqf36', ], 'navigator' => [ 'finish' => '', ], ]); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertTrue($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isFinishAction()); self::assertTrue($button->isClicked()); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); $data = $flow->getData(); self::assertSame('John', $data['firstName']); self::assertSame('Doe', $data['lastName']); self::assertTrue($data['worker']); self::assertSame('Acme', $data['company']); self::assertSame('ROLE_DEVELOPER', $data['role']); self::assertSame('john@acme.com', $data['email']); self::assertSame('eBvU2vBLfSXqf36', $data['password']); } public function testHandleActionManually() { $flow = $this->factory->create(UserSignUpType::class, new UserSignUp()); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); $flow->submit([ 'personal' => [ 'firstName' => 'John', 'lastName' => 'Doe', 'worker' => '1', ], 'navigator' => [ 'next' => '', ], ]); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertNotNull($actionButton = $flow->getClickedButton()); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); $actionButton->handle(); self::assertSame('professional', $flow->getCursor()->getCurrentStep()); } public function testAddFormErrorOnActionHandling() { $flow = $this->factory->create(UserSignUpType::class, new UserSignUp()); $flow->get('navigator')->add('next', NextFlowType::class, [ 'handler' => static function (mixed $data, ButtonFlowInterface $button, FormFlowInterface $flow) { $flow->addError(new FormError('Action error')); }, ]); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); $flow->submit([ 'personal' => [ 'firstName' => 'John', 'lastName' => 'Doe', ], 'navigator' => [ 'next' => '', ], ]); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertNotNull($actionButton = $flow->getClickedButton()); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); $actionButton->handle(); $flow = $flow->getStepForm(); $errors = $flow->getErrors(true); self::assertFalse($flow->isValid()); self::assertCount(1, $errors); self::assertSame('Action error', $errors->current()->getMessage()); self::assertSame('personal', $flow->getCursor()->getCurrentStep()); } public function testStepValidationGroups() { $data = new UserSignUp(); $data->worker = true; $flow = $this->factory->create(UserSignUpType::class, $data); // Check that validation groups include the current step name self::assertSame(['Default', 'personal'], $flow->getConfig()->getOption('validation_groups')($flow)); // Move to next step $flow->moveNext(); $flow = $flow->newStepForm(); // Check that validation groups are updated self::assertEquals(['Default', 'professional'], $flow->getConfig()->getOption('validation_groups')($flow)); } public function testLastStepSkippedMarkFlowAsFinished() { $flow = $this->factory->create(LastStepSkippedType::class, ['currentStep' => 'step1']); self::assertSame('step1', $flow->getCursor()->getCurrentStep()); self::assertFalse($flow->isSubmitted()); self::assertNull($flow->getClickedButton()); self::assertTrue($flow->has('step1')); self::assertTrue($flow->has('navigator')); $navigatorForm = $flow->get('navigator'); self::assertCount(2, $navigatorForm->all()); self::assertTrue($navigatorForm->has('next')); self::assertTrue($navigatorForm->has('reset')); $flow->submit([ 'step1' => 'foo', 'navigator' => [ 'next' => '', ], ]); self::assertSame('step1', $flow->getCursor()->getCurrentStep()); self::assertTrue($flow->isSubmitted()); self::assertTrue($flow->isValid()); self::assertFalse($flow->isFinished()); self::assertNotNull($button = $flow->getClickedButton()); self::assertTrue($button->isNextAction()); self::assertTrue($button->isClicked()); $button->handle(); // $flow->moveNext() is called internally self::assertTrue($flow->isFinished()); self::assertNotSame($flow, $flow->getStepForm()); self::assertSame(['currentStep' => 'step1', 'step1' => 'foo'], $flow->getData()); } }