From ad4fd788df64956fb2d10a6df2bfd70f74e0662c Mon Sep 17 00:00:00 2001 From: Sergei Maertens Date: Thu, 24 Nov 2022 18:34:29 +0100 Subject: [PATCH] :pencil: [#1068] -- document formio service and utilities --- docs/developers/backend/core/formio.rst | 134 ++++++++++++++++++ docs/developers/backend/index.rst | 1 + docs/developers/backend/modules/index.rst | 12 +- .../formio/dynamic_config/__init__.py | 2 - src/openforms/formio/service.py | 6 +- 5 files changed, 143 insertions(+), 12 deletions(-) create mode 100644 docs/developers/backend/core/formio.rst diff --git a/docs/developers/backend/core/formio.rst b/docs/developers/backend/core/formio.rst new file mode 100644 index 0000000000..fa0b718715 --- /dev/null +++ b/docs/developers/backend/core/formio.rst @@ -0,0 +1,134 @@ +.. _developers_backend_core_formio: + +=========================== +Core: formio.io integration +=========================== + +Open Forms uses `form.io`_ under the hood to build and render forms, and then adds its +own layers on top of that, such as: + +* implementing multi-step forms where every step is a form.io definition +* evaluating backend logic using data from earlier steps +* dynamically adapting form.io definitions as needed + +This means that we process the form.io datastructures in the backend, using Python. All +the code for this is organized in the ``openforms.formio`` package. + +.. versionchanged:: 2.1.0 + + ``openforms.custom_field_types`` was refactored into the ``openforms.formio`` package, + and all of the separate registries (formatters, normalizers...) were merged into a + single compoment registry. + +Supported features +================== + +.. currentmodule:: openforms.formio.service + +Formatting values for display +----------------------------- + +Value formatting is done for displaying form submission data summaries, rendering +confirmation PDFs and emails... It is aware if it's in a HTML context or not. It is +heavily used in the :ref:`renderers `. + +Whenever a component plugin is registered, the +:attr:`openforms.formio.registry.BasePlugin.formatter` class attribute **must** be +specified. + +.. autofunction:: format_value + :noindex: + + +Normalizing input data +---------------------- + +Data for a component can be sourced from external systems that employ different +formatting rules compared to what form.io expects. Normalizing this data helps to be +able to make proper comparisons at different stages in the submission life-cycle. + +You can opt-in to this by configuring :attr:`openforms.formio.registry.BasePlugin.normalizer`. + +.. autofunction:: normalize_value_for_component + :noindex: + + +Dynamically modifying component configuration +--------------------------------------------- + +Certain component types require on-the-fly configuration rewriting, such as applying +global configuration options that may change independently from when the form is +actually being designed. + +Dynamic rewriting is enabled by implementing +:meth:`openforms.formio.registry.BasePlugin.mutate_config_dynamically`. It receives the +current :class:`openforms.submissions.models.Submission` instance and a mapping of all +the variable names and values at the time. + +.. autofunction:: get_dynamic_configuration + :noindex: + +For an example of a custom field type, see :class:`openforms.formio.components.custom.Date`. + +Finally, the resulting resolved component definitions are evaluated with the template +engine where variable values are evaluated for compoment labels, descriptions... and +configuration based on the HTTP request is performed (see +:func:`openforms.formmio.service.rewrite_formio_components_for_request`). + +Reference +========= + +Public API - ``openforms.formio.service`` +----------------------------------------- + +.. automodule:: openforms.formio.service + :members: + +.. autoclass:: openforms.formio.registry.BasePlugin + :members: + :exclude-members: verbose_name + +Extending +--------- + +Using our :ref:`usual extension pattern ` you can register your +own types. + +Extensions should inherit from :class:`openforms.formio.registry.BasePlugin` or +implement the same protocol(s) and be registered with their form.io type: + +.. code-block:: python + + from openforms.formio.formatters.formio import DefaultFormatter + from openforms.formio.registry import BasePlugin + + @register("myCustomType") + class MyComponent(BasePlugin): + formatter = DefaultFormatter + + +You can find some examples in ``openforms.formio.components.custom``. + + +Private API +----------- + +Module: ``openforms.formio.dynamic_config`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: openforms.formio.dynamic_config + :members: + +Module: ``openforms.formio.formatters`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: openforms.formio.formatters + :members: + +Module: ``openforms.formio.rendering`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. automodule:: openforms.formio.rendering + :members: + +.. _form.io: https://www.form.io/ diff --git a/docs/developers/backend/index.rst b/docs/developers/backend/index.rst index 8f7cd34f9e..6860596734 100644 --- a/docs/developers/backend/index.rst +++ b/docs/developers/backend/index.rst @@ -44,6 +44,7 @@ Core :maxdepth: 1 core/index + core/formio core/submissions core/submission-renderer core/variables diff --git a/docs/developers/backend/modules/index.rst b/docs/developers/backend/modules/index.rst index 940d168fc5..01d3184b70 100644 --- a/docs/developers/backend/modules/index.rst +++ b/docs/developers/backend/modules/index.rst @@ -1,8 +1,8 @@ .. _developers_backend_modules_index: -======= -Modules -======= +===================== +Modules: introduction +===================== Open Forms groups functionalities in *modules*. Within a module there are often one or more plugins available for a vendor-specific implementation of the high-level @@ -10,9 +10,3 @@ functionality. Modules can usually be :ref:`extended ` wit plugins. .. todo:: This documentation is incomplete - -.. toctree:: - :caption: Contents - :maxdepth: 2 - - dmn diff --git a/src/openforms/formio/dynamic_config/__init__.py b/src/openforms/formio/dynamic_config/__init__.py index 71ea9ab702..dfb0afbda1 100644 --- a/src/openforms/formio/dynamic_config/__init__.py +++ b/src/openforms/formio/dynamic_config/__init__.py @@ -1,7 +1,5 @@ """ Implement component-specific dynamic configuration based on (submission) state. - -This will eventually replace ``openforms.forms.custom_field_types``. """ from typing import Optional diff --git a/src/openforms/formio/service.py b/src/openforms/formio/service.py index faf101c2ae..956eb62a61 100644 --- a/src/openforms/formio/service.py +++ b/src/openforms/formio/service.py @@ -38,6 +38,9 @@ def format_value(component: Component, value: Any, as_html: bool = False): + """ + Format a submitted value in a way that is most appropriate for the component type. + """ return register.format(component, value, as_html=as_html) @@ -59,7 +62,8 @@ def get_dynamic_configuration( """ Given a static Formio configuration, apply the hooks to dynamically transform this. - The configuration is modified in the context of the provided :arg:`submission`. + The configuration is modified in the context of the provided ``submission`` + parameter. """ rewrite_formio_components(config_wrapper, submission=submission, data=data)