Dynamic structure blueprint

Iā€™m writing a form builder plugin and to display the collected data of a form I need a dynamic structure. Here is an example to clarify what I mean:

A user creates a form with a first_name and a last_name field with the form builder plugin. Than this form can be used to collect data. The form builder plugin stores this data as entries in a structure field. To display this data in the panel I need to set the fields of the structure. But because the fields are created dynamically by the user I canā€™t write them in the blueprint directly. Is there a way to generate the fields for the structure dynamically? Something like this (where generateFields could be defined in the page controller):

form_entries:
  type: structure
  fields: {{ generateFields() }}

which would be resolved to the following the example above:

form_entries:
  type: structure
  fields:
    first_name:
      type: text
    last_name:
      type: text

@arnoson did You succeed? Looking for solution for same problem - how to dynamically create blueprint structure.

If you can access the page where the data is stored directly (e.g page(ā€˜somepageā€™), you could create the blueprint dynamically:

2 Likes

Dynamically created page from received data with Page::create.
Problem is - that I can not see that page in panel, because it does not have appropriate blueprint.

Two points that I do not understand:

  1. how can I get received data in blueprint plugin (so I could iterate through data and create dynamic page fields).
  2. If amount of page fields varies - does it means that I need to create blueprint for each situation - survey3.yaml survey7.yaml etc

The problem with dynamic blueprints is that ā€“ as I wrote in the recipe and mentioned above ā€“ you donā€™t have access to the current page object. You can fetch a specific page via the page helper, but that doesnā€™t really make sense if you have multiple pages created programmatically.

So I have /controllers/upload.php which receives data when frontend sends data to /templates/upload.php which calls Page::create($params).

Got a bit confused - Page::create has props: ā€œtemplateā€ which actually is name of blueprint, but there is also prop ā€œblueprintā€ which sets blueprint object? Was trying to define blueprint fields hereā€¦ could not manage to work it.

What I want to achieve - in same place where I create page (with received data) would like before or after define and create blueprint for that page (with defined text fields for each received form input).

Normally my blueprint would look like this:

name:
  label: Name
  type: text
surname:
  label: Surname
  type: text
question1:
  label: Question 1
  type: text
question2:
  label: Question 2
  type: text
... etc

One user will answer on 3 questions, other user will answer on 7 questions. I could hardcode maximum possible question fields in blueprint, but instead want to create that blueprint dynamically in moment when receive data from frontend.

Wouldnā€™t it make more sense to store the answers in a structure field in this case, where the number of entries doesnā€™t matter?

@texnixe also thought about this as option B, will try this way. Thank You!

I have blueprint like @arnoson where I can define form fields like structure items and I wanā€™t define submissions fields for this dynamic form fields. I understand correctly that this is not possible?

Thanks

Look into programmable blueprints: Programmable blueprints | Kirby CMS

Should work fine for this use case.

But I need reuse blueprint for multiple pages. How can I get actual form fields for submissions fields definition if current page is not accessible? Thanks

Oh, ok, then this approach doesnā€™t work. Maybe store it in some other format instead, JSON for example.

And how can I show this type of submission format in panel? Thanks

Just as Information or editable?

Just as information. And exportable would be perfect :slight_smile:

Just as information you could output the content of the stored json in an info field (via a custom page method that outputs some html).

With JSON, you can export as anything.

Can you share some links to detailed informations about that? Thanks!

Info field: Info | Kirby CMS
Field method: Field methods | Kirby CMS

In your info field you would do something like this:

fields:
  info:
  type: info
  theme: neutral
  text: "{< page.jsonFieldName.toText >}"

In your toText() custom field method, you would generate the output for the field.

OK, so if Iā€™m understand correctly.

  1. I need to save form submission to predefined page field in json format (some link for this would be perfect :slight_smile:
  2. Define custom field method which transform json to html
  3. Define info field where I can output submissions field as html

Correct?

I have this for saving form data to structure field:

function addToStructure($page, $field, $data = array()){
    $kirby = kirby();
    $kirby->impersonate('kirby');

    $fieldData = page($page)->$field()->yaml();
    $fieldData[] = $data;
    $fieldData = yaml::encode($fieldData);

    try {
        page($page)->update(array($field => $fieldData));
        return true;
    } catch(Exception $e) {
        return $e->getMessage();
    }
}