### Generate Dynamic Form Content Based on Previous Step Data in PHP Source: https://context7.com/yceruto/formflow-demo/llms.txt Creates a form step that dynamically generates its fields and options based on data submitted in a previous step. It accesses the parent form's data using `$builder->getData()` and uses it to populate choices for a `ChoiceType` field. This example includes a helper method to adjust color brightness for gradient options. ```php getData(); assert(is_string($colorPicker->mainColor), 'Main color must be a string'); // Generate dynamic choices based on previous step $gradients = [ 'Lighter' => $this->adjustBrightness($colorPicker->mainColor, 40), 'Original' => $colorPicker->mainColor, 'Darker' => $this->adjustBrightness($colorPicker->mainColor, -40), ]; $builder->add('gradientColor', ChoiceType::class, [ 'label' => 'Gradient Color', 'choices' => $gradients, 'choice_label' => function ($choice, $value) { return $value . ' (' . $choice . ')'; }, ]); } private function adjustBrightness(string $hexColor, int $amount): string { $hex = ltrim($hexColor, '#'); $r = max(0, min(255, hexdec(substr($hex, 0, 2)) + $amount)); $g = max(0, min(255, hexdec(substr($hex, 2, 2)) + $amount)); $b = max(0, min(255, hexdec(substr($hex, 4, 2)) + $amount)); return sprintf("#%02X%02X%02X", $r, $g, $b); } } ``` -------------------------------- ### Custom Form Navigator with Conditional Buttons (PHP) Source: https://context7.com/yceruto/formflow-demo/llms.txt This PHP class extends Symfony's `AbstractType` to create a custom form navigator for multi-step forms. It defines various navigation buttons like 'Start Over', 'Back', 'Continue', 'Upload Documents', and 'Submit KYC'. The 'Continue' button's visibility is conditionally controlled based on the current form step and the ability to move to the next step. ```php add('reset', ResetFlowType::class, [ 'label' => 'Start Over', ]) ->add('back', PreviousFlowType::class, [ 'label' => 'Back', ]) ->add('next', NextFlowType::class, [ 'label' => 'Continue', // Conditionally show based on current step and ability to move 'include_if' => fn (FormFlowCursor $cursor): bool => $cursor->getCurrentStep() !== 'documents' && $cursor->canMoveNext(), ]) ->add('upload', UploadFlowType::class, [ 'label' => 'Upload Documents', ]) ->add('finish', FinishFlowType::class, [ 'label' => 'Submit KYC', ]); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'label' => false, 'mapped' => false, 'priority' => -100, ]); } } ``` -------------------------------- ### Basic Form Flow Controller Implementation Source: https://context7.com/yceruto/formflow-demo/llms.txt This PHP code demonstrates how to implement a basic FormFlow controller in Symfony. It creates a form flow, handles requests, checks for submission and validity, and renders the current step's form. It requires the FormFlowInterface and relevant form types. ```php createForm(BasicType::class, new BasicDto()) ->handleRequest($request); if ($flow->isSubmitted() && $flow->isValid() && $flow->isFinished()) { // Process completed flow data $data = $flow->getData(); $this->addFlash('success', 'Your form flow was successfully finished!'); return $this->redirectToRoute('app_demo_basic'); } return $this->render('demo/basic.html.twig', [ 'form' => $flow->getStepForm(), ]); } } ``` -------------------------------- ### Generating and Using Custom Self-Signed TLS Certificates with mkcert Source: https://github.com/yceruto/formflow-demo/blob/main/docs/tls.md Steps to generate self-signed TLS certificates using mkcert and configure Caddy to use them. This involves creating a certificates directory, generating the certs, updating the compose override file with environment and volume configurations, and restarting the service. ```bash mkdir -p frankenphp/certs mkcert -cert-file frankenphp/certs/tls.pem -key-file frankenphp/certs/tls.key "server-name.localhost" ``` ```diff php: environment: + CADDY_SERVER_EXTRA_DIRECTIVES: "tls /etc/caddy/certs/tls.pem /etc/caddy/certs/tls.key" # ... volumes: + - ./frankenphp/certs:/etc/caddy/certs:ro # ... ``` -------------------------------- ### Custom Step Rendering in Twig Source: https://context7.com/yceruto/formflow-demo/llms.txt This Twig template demonstrates how to create a custom layout for a multi-step form. It includes logic to render specific blocks for different form steps, such as handling file uploads for a 'documents' step and displaying previously uploaded file paths. It also manages navigation buttons dynamically based on their presence. ```twig {# templates/demo/kyc/flow.html.twig #} {% extends 'base.html.twig' %} {% block body %}
{{ form_start(form, {attr: {enctype: 'multipart/form-data'}}) }}
{{ include('demo/kyc/_progress.html.twig') }}
{% set current_step = form.vars.cursor.currentStep %} {% set current_step_block_name = 'kyc_' ~ current_step ~ '_step' %}
{{ field_label(form[current_step]) }}

{{ field_help(form[current_step]) }}


{# Render custom block or default #} {% if block(current_step_block_name) is defined %} {{ block(current_step_block_name) }} {% else %} {{ block('kyc_default_step') }} {% endif %}
{{ block('kyc_navigator') }}
{{ form_end(form) }}
{% endblock %} {% block kyc_default_step %} {{ form_widget(form[current_step]) }} {% endblock %} {% block kyc_documents_step %} {% set data = form.vars.data %}
{{ form_row(form.documents.idDocumentFile) }} {# Show previously uploaded files #} {% if data.documents.idDocumentPath|default(false) %}
ID Document: {{ data.documents.idDocumentPath }} (uploaded)
{% endif %}
{{ form_row(form.documents.proofOfAddressFile) }} {% if data.documents.proofOfAddressPath|default(false) %}
Proof of Address: {{ data.documents.proofOfAddressPath }} (uploaded)
{% endif %}
{% endblock %} {% block kyc_navigator %}
{% if form.navigator.back is defined %} {{ form_widget(form.navigator.back, {attr: {class: 'btn-outline-dark'}}) }} {% endif %}
{% if form.navigator.upload is defined %} {{ form_widget(form.navigator.upload, {attr: {class: 'btn-dark'}}) }} {% endif %} {% if form.navigator.next is defined %} {{ form_widget(form.navigator.next, {attr: {class: 'btn-dark'}}) }} {% endif %} {% if form.navigator.finish is defined %} {{ form_widget(form.navigator.finish, {attr: {class: 'btn-dark'}}) }} {% endif %}
{% endblock %} ``` -------------------------------- ### Disabling HTTPS for Local Development Source: https://github.com/yceruto/formflow-demo/blob/main/docs/tls.md Instructions to disable HTTPS and enable HTTP for local development by setting specific environment variables and running the Docker Compose command. This ensures the application is accessible via HTTP. ```bash SERVER_NAME=http://localhost \ MERCURE_PUBLIC_URL=http://localhost/.well-known/mercure \ docker compose up --wait ``` -------------------------------- ### Implement Conditional Steps with Skip Logic in PHP Source: https://context7.com/yceruto/formflow-demo/llms.txt Builds a multi-step form flow with conditional steps using `AbstractFlowType`. It utilizes skip logic defined as closures to determine whether a step should be displayed based on the form data. This enables dynamic form flows tailored to user selections, such as choosing between individual or organization accounts. ```php addStep('type', AccountTypeSelectionType::class); // Conditional step: only shown for individual accounts $builder->addStep('individual', IndividualType::class, skip: fn (SignUpDto $data) => $data->type !== 'individual' ); // Conditional step: only shown for organization accounts $builder->addStep('organization', OrganizationType::class, skip: fn (SignUpDto $data) => $data->type !== 'organization' ); $builder->addStep('credentials', CredentialsType::class); $builder->addStep('confirmation', ConfirmationType::class); $builder->add('navigator', SignUpNavigatorType::class); } } ``` -------------------------------- ### PHP Controller for Query Parameter Step Selection Source: https://context7.com/yceruto/formflow-demo/llms.txt This PHP controller manages a multi-step form using Symfony's FormFlow. It handles form submissions, validates data, saves the account information, and allows step selection through a query parameter ('tab'). It depends on AccountRepositoryInterface and SettingsType. ```php repository->current(); /** @var FormFlowInterface $form */ $form = $this->createForm(SettingsType::class, $account, ['tab' => $tab]) ->handleRequest($request); if ($form->isSubmitted() && $form->isValid() && null === $form->getClickedButton()) { $this->repository->save($account); $this->addFlash('success', 'Your information has been updated!'); return $this->redirectToRoute('app_demo_settings', ['tab' => $tab]); } return $this->render('demo/settings/form.html.twig', [ 'form' => $form->getStepForm(), ]); } } ``` -------------------------------- ### Non-Linear Navigation with Null Data Storage in PHP Source: https://context7.com/yceruto/formflow-demo/llms.txt Configures a form flow that supports non-linear navigation by disabling session data storage using NullDataStorage. It defines multiple steps for settings and uses a custom step accessor for navigation. Requires Symfony Form components. ```php addStep('details', DetailsType::class); $builder->addStep('profile', ProfileType::class); $builder->addStep('team', TeamType::class); $builder->addStep('notification', NotificationType::class); } public function configureOptions(OptionsResolver $resolver): void { $resolver->define('tab')->required()->allowedTypes('string'); $resolver->setDefaults([ 'data_class' => Account::class, 'data_storage' => new NullDataStorage(), // No session storage 'step_accessor' => fn (Options $options) => new FixedStepAccessor($options['tab']), ]); } } ``` -------------------------------- ### Handle File Uploads in Multi-Step Forms (PHP) Source: https://context7.com/yceruto/formflow-demo/llms.txt This PHP class handles file uploads for multi-step forms, including ID documents and proof of address. It saves uploaded files to a specified directory, generates unique filenames, and removes old files when new ones are uploaded. It depends on Symfony's Filesystem and Slugger components. ```php idDocumentFile instanceof UploadedFile) { if ($dto->idDocumentPath) { $this->removeFile($dto->idDocumentPath); } $dto->idDocumentPath = $this->saveFile($dto->idDocumentFile); $dto->idDocumentFile = null; // Clear to avoid session serialization issues } // Handle proof of address upload if ($dto->proofOfAddressFile instanceof UploadedFile) { if ($dto->proofOfAddressPath) { $this->removeFile($dto->proofOfAddressPath); } $dto->proofOfAddressPath = $this->saveFile($dto->proofOfAddressFile); $dto->proofOfAddressFile = null; } } private function saveFile(UploadedFile $file): string { $originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME); $safeFilename = $this->slugger->slug($originalFilename); $fileName = $safeFilename.'-'.uniqid().'.'.$file->guessExtension(); $file->move($this->uploadDirectory, $fileName); return $fileName; } private function removeFile(string $filePath): void { $this->filesystem->remove($this->uploadDirectory.DIRECTORY_SEPARATOR.$filePath); } } ``` -------------------------------- ### Twig Template for Rendering Flow Forms Source: https://context7.com/yceruto/formflow-demo/llms.txt This Twig template renders a multi-step form generated by Symfony's FormFlow component. It extends a base template and displays the form fields. It also shows how to access and display the current step and total number of steps in the form flow. ```twig {# templates/demo/basic.html.twig #} {% extends 'base.html.twig' %} {% block body %}

Basic

{{ form(form) }} {# Access flow cursor information #} Step {{ form.vars.cursor.stepIndex + 1 }} of {{ form.vars.cursor.totalSteps }}
{% endblock %} ``` -------------------------------- ### Defining a Multi-Step Form Flow Type Source: https://context7.com/yceruto/formflow-demo/llms.txt This PHP code defines a multi-step form flow using Symfony's AbstractFlowType. It sets up sequential steps, specifies the data class for the flow, and includes a navigator component. Dependencies include FormFlowBuilderInterface and various step form types. ```php addStep('step1', Step1Type::class); $builder->addStep('step2', Step2Type::class); $builder->addStep('step3', Step3Type::class); // Add navigation buttons $builder->add('navigator', NavigatorFlowType::class); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => BasicDto::class, 'step_property_path' => 'currentStep', // Tracks current step in DTO ]); } } ``` -------------------------------- ### Custom Step Accessor for Fixed Step in PHP Source: https://context7.com/yceruto/formflow-demo/llms.txt Provides a custom implementation of StepAccessorInterface to enforce a fixed step in a form flow, preventing step changes from being persisted. This is useful for specific navigation control scenarios. Requires Symfony Form components. ```php step; // Always return fixed step } public function setStep(object|array &$data, string $step): void { // No-op: don't store step changes } } ``` -------------------------------- ### Trusting Caddy's Local Certificate Authority on Host Machines Source: https://github.com/yceruto/formflow-demo/blob/main/docs/tls.md Commands to add the Caddy local Certificate Authority (CA) root certificate to the host's trust store for different operating systems. This is necessary because certificates signed by the Caddy CA are not trusted by default. ```shell # Mac $ docker cp $(docker compose ps -q php):/data/caddy/pki/authorities/local/root.crt /tmp/root.crt && sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /tmp/root.crt # Linux $ docker cp $(docker compose ps -q php):/data/caddy/pki/authorities/local/root.crt /usr/local/share/ca-certificates/root.crt && sudo update-ca-certificates # Windows $ docker compose cp php:/data/caddy/pki/authorities/local/root.crt %TEMP%/root.crt && certutil -addstore -f "ROOT" %TEMP%/root.crt ``` -------------------------------- ### Pass Data to Dynamic Steps in PHP Source: https://context7.com/yceruto/formflow-demo/llms.txt Illustrates how to pass data to a subsequent step within a Symfony Form Flow. When `inherit_data` is enabled in a child form, you can explicitly set the `data` option for a step in the `buildFormFlow` method. This ensures that the child step has access to the data from the parent or previous steps, as demonstrated with `Step2Type`. ```php addStep('step1', Step1Type::class); // Pass data to step when inherit_data is true $builder->addStep('step2', Step2Type::class, [ 'data' => $builder->getData(), // Required for accessing data in Step2Type ]); $builder->add('navigator', NavigatorFlowType::class); } } ``` -------------------------------- ### Create Step-Specific Form Types in PHP Source: https://context7.com/yceruto/formflow-demo/llms.txt Defines a specific form type for a step in a multi-step form. It extends `AbstractType` and configures default options, including the data class and enabling data inheritance from the parent form. This is useful for organizing complex forms into manageable, step-by-step components. ```php add('field11') ->add('field12', TextareaType::class); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ 'data_class' => BasicDto::class, 'inherit_data' => true, // Share data with parent form ]); } } ``` -------------------------------- ### Custom Button Flow Type with Handler in PHP Source: https://context7.com/yceruto/formflow-demo/llms.txt Implements a custom flow type that intercepts button clicks to execute custom logic before proceeding to the next step. It uses a DocumentUploadHandler to process file uploads. Dependencies include Symfony Form components. ```php setDefaults([ 'handler' => function (mixed $data, ButtonFlowInterface $button, FormFlowInterface $flow): void { /** @var KycDto $data */ $data = $flow->getData(); // Custom logic: handle file uploads before moving $this->uploadHandler->handleUpload($data->documents); // Move to next step $flow->moveNext(); }, 'include_if' => fn (FormFlowCursor $cursor): bool => $cursor->getCurrentStep() === 'documents' && $cursor->canMoveNext(), ]); } public function getParent(): string { return NextFlowType::class; } } ``` -------------------------------- ### Nested DTOs for Complex Form Structures in PHP Source: https://context7.com/yceruto/formflow-demo/llms.txt This PHP code defines a Data Transfer Object (DTO) for a sign-up process, illustrating the use of nested DTOs to represent complex, hierarchical form data. It utilizes Symfony's validator constraints to define validation rules for different sections of the form and for specific validation groups, allowing for conditional validation based on the form step. ```php