Workflow Transition Forms 

Configuration 

Sometimes the data available in the system is not enough to progress the workflow automatically by clicking one button. Therefore, users have to provide additional data in UI forms to be able to proceed (from several fields to complex entities).

Workflow transitions can be configured to handle custom data provided by a user by displaying a form on the UI before a transition commit happens. Examples below illustrate the common ways to configure transition forms.

Simple Example 

Suppose we have a workflow that handles only one required data input from a user.

workflows:
    greeting_flow:
        entity: Oro\Bundle\UserBundle\Entity\User
        entity_attribute: user
        defaults: { active: true }
        attributes:
            the_message:
                type: string
        steps:
            congratulated:
                allowed_transitions: [ congratulate_with ]
        transitions:
            congratulate_with:
                is_start: true
                step_to: congratulated
                form_options:
                    attribute_fields:
                        the_message:
                            options:
                                constraints:
                                    - NotBlank: ~
                destination_page: view
                transition_definition: message_definition
        transition_definitions:
            message_definition:
                actions:
                    - '@flash_message': {message: $.data.the_message, type: success}

Above is a simple working example of a cycled workflow with one step and one transition. On transition congratulate_with, we should force the user to fill a text input in the the_message field that corresponds to our configured workflow attribute. The field is also required by constraints in form attribute_fields options. Then, we can submit it as a transition payload. Next, we should see a @flash_message with the text we prompt on the dialog (the default for transition display_type) that is flashed on the entity view page.

Extended Example 

Custom types and form_init:

workflows:
    user_update_flow:
        entity: Oro\Bundle\UserBundle\Entity\User
        entity_attribute: user
        defaults: { active: true }
        attributes:
            my_message:
                type: string
            my_dote:
                type: object
                options:
                    class: DateTime
        steps:
            congratulated:
                allowed_transitions: [ congratulate_with ]
        transitions:
            congratulate_with:
                is_start: true
                step_to: congratulated
                form_options:
                    form_init:
                        - '@create_object':
                            class: \DateTime
                            attribute: $.data.my_date
                            parameters: ['tomorrow']
                    attribute_fields:
                        my_message:
                            options:
                                constraints:
                                    - NotBlank: ~
                        my_date:
                            form_type: my_date_picker #here your custom date picker
                destination_page: view
                transition_definition: message_definition
        transition_definitions:
            message_definition:
                actions:
                    - '@flash_message': {message: $my_message, type: success}

If we need a more complex form to be filled by a user who is performing a transition, we need to specify fields for the data that we need. But before that, let us prepare the data that will be displayed to a user in form_init.

form_init

The form_init node is under form_options. It is an action that will be performed before form rendering (see Action Component for more details). Here, you can prepare your data before form rendering. In the sample configuration we are creating, a new \DateTime object is pre-configured to tomorrow. So that on our custom “my_date_picker” type we will see the day after today predefined on the form.

Custom Form Type Example 

You can also use your custom form type for the whole transition handling. Have a look at the example below:

workflows:
    quote_update_circular:
        entity: Oro\Bundle\CustomerBundle\Entity\CustomerUser
        entity_attribute: customer_user
        defaults: {active: true}
        attributes:
           quote: #here we will store our form data result
               type:  entity
               options:
                   class: Oro\Bundle\SaleBundle\Entity\Quote
        steps:
            quote:
                allowed_transitions:
                    - transit_quote
        transitions:
            transit_quote:
                step_to: quote
                is_start: true
                transition_definition: quote_update_definition
                display_type: dialog
                form_type: 'Oro\Bundle\SaleBundle\Form\Type\QuoteType' #define a custom form type to use for transit
                form_options:
                    configuration: #define configuration for the custom form type
                        handler: 'default' #which handler should process the from (custom form transition handler)
                        template: '@OroSale/Quote/update.html.twig' #our complex form page template
                        data_provider: 'quote_update' #template context data provider that will provide data for the template
                        data_attribute: 'quote' #attribute to store form data and get from
                    form_init: #here we will prepare our form
                        - '@tree':
                            conditions: #if no quote is defined in our worfklow data ... ->
                                '@empty': [$quote]
                            actions:
                                - '@create_object': #.. -> we will create it
                                    class: Oro\Bundle\SaleBundle\Entity\Quote
                                    attribute: $.data.quote # and set to our data_attribute defined in configuration
                                    parameters: ~
                        - '@assign_value': #add some more preparation of the form data object below by WF entity data
                            attribute: $.data.quote.customerUser
                            value: $customer_user
                        - '@assign_value':
                            attribute: $.data.quote.customer
                            value: $customer_user.customer
                    attribute_fields: ~ #attribute fields should be ommited as we use totally custom form type
        transition_definitions:
            quote_update_definition:
                actions:
                    - '@flash_message':
                        message: 'Workflow transited. Entity updated!'
                        type: 'success'
                    - '@redirect': {route: 'oro_sale_quote_index'}

Here, the configured workflow creates a new Quote from the start on Customer User page and performs updates for the Quote circularly in each transition, because it brings us back to the same step.

Now, let’s look at configuration specific moments.

To use your custom form type that replaces the default transition form, set the type in form_type option to your custom type.

Note

FQCN should be used as the value for form_type when defining custom form type and this form must be resolvable by “Form Registry”. Together with that, you must specify the correct configuration for the type customization (handler, template, data_provider, data_attribute options). Here, we have Oro\Bundle\SaleBundle\Form\Type\QuoteType form type. But to handle this complex form type properly, specify additional options in the form_options.configuration node.

They are:

  • handler - an alias of a registered service by tag oro_form.registry.form_handler. You can use the default one by passing ‘default’. See more about form update handler in Update Handler.

  • template - the name of a template that should be used for the custom form, the default value is @OroWorkflow/actions/update.html.twig, and this template can be used as a starting point for customizations.

Note

It should be extended from @OroUI/actions/update.html.twig for compatibility with transition form page (usually all Oro update templates do so).

  • data_provider - an alias of a registered service by tag oro_form.form_template_data_provider that implements Oro\Bundle\FormBundle\Provider\FormTemplateDataProviderInterface. It should return all necessary data for specified template as controllers usually do.

  • data_attribute - the name of data attribute where form data payload should be taken from by workflow engine to pass into form and put to as result of handling.

Form Reuse Recommendation 

The best approach when creating a new entity management (entity controller) while developing is to use the Oro\Bundle\FormBundle\Model\UpdateHandlerFacade::update method functionality. So that if you encapsulate your logic into proper parts of the form handling process, then you should easily be able to create a workflow with the custom form type. As custom form workflow transition handling is based on reusing those parts in transition configuration.

Transition Forms and Layouts 

For layout based sites, use the Layout Update functionality to the UI customization capabilities of a transition form.

First, make sure you are familiar with the type of interface build, so that you could proceed with managing layout-based transition forms.

Layout Imports for New Controllers 

There are several major imports that can handle the next types of transition forms:

Please consider adding them to your custom transition form controller.

Context Data 

The following layout context variables are available for the transition forms:

  • workflowName - the name of a workflow

  • transitionName - the name of a transition

  • transitionFormView - the form view instance (used in rendering)

  • transition - the instance of Transition class that current transit corresponds to

  • workflowItem - the instance of WorkflowItem - current workflow record representation

  • formRouteName - the route that should be populated by LayoutTransitionContext processor in TransitionContext

Limitations 

A workflow transition form does not have layout form provider. So you cannot reuse it in other layouts. It is a known drawback, but the transition process is quite complex, and transition form reusage could make data dependency management quite complicated.