Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

nickdavies07's avatar

Creating Separate Seeder Classes For Seeding Template Data

Need a bit of advice on the best approach here.

At present, we have a form_templates table, which users can use to create a new form, based off the template definition which is stored as JSON.

These are all initially seeded via a SQL file; however the issue now is when we come to try and update these, it can be difficult to figure out which ones might need updating as we have to query the nested JSON data to figure out which field to update. Some of these fields in the JSON need IDs from other tables as well.

An example of one of the smaller sets of data in the JSON column:

[{"id":"0_date_input","db_id":4890,"field_id":13,"field_type":"date_input","field_type_name":"Date Input","component":"DateInput","keywords":"","description":"","instructions":"","has_min_max_fields":1,"has_mandatory_field":1,"is_min_max_date":1,"attributes":{"name":"Date","value":null,"min":null,"max":null}},{"id":"1_largetext","db_id":4891,"field_id":9,"field_type":"largetext","field_type_name":"Multi Line Text Input","component":"Largetext","keywords":"","description":"","instructions":"","has_min_max_fields":1,"has_mandatory_field":1,"is_min_max_date":0,"attributes":{"name":"Action\/ response required","value":null,"min":null,"max":null}},{"id":"2_yes_no","db_id":4892,"field_id":2,"field_type":"yes_no","field_type_name":"Yes or No","component":"YesNo","keywords":"","description":"","instructions":"","has_min_max_fields":0,"has_mandatory_field":1,"is_min_max_date":0,"attributes":{"name":"Has this been completed?","value":null}},{"id":"3_override_date_input","db_id":4893,"field_id":14,"field_type":"override_date_input","field_type_name":"Override Date Input","component":"OverrideDateInput","keywords":"","description":"","instructions":"","has_min_max_fields":1,"has_mandatory_field":0,"is_min_max_date":1,"attributes":{"name":"Date completed?","value":null,"min":null,"max":null,"required":true}},{"id":"4_signature_image","db_id":4894,"field_id":11,"field_type":"signature_image","field_type_name":"Signature Image","component":"SignatureImage","keywords":"","description":"","instructions":"","has_min_max_fields":0,"has_mandatory_field":1,"is_min_max_date":0,"attributes":{"name":"Signature","value":"images\/empty_signature.png"},"isFileField":true,"isFileSavable":false}]

A solution I've found that will work better than having to query this in a migration is to have a separate database seeder for each form template, with the above definition defined as an array, that can easily be changed.

Something like this:

<?php

namespace App\Modules\FormBuilder\Templates;

use App\Modules\Files\Models\SharedAsset;

class AccidentInjuryFormTemplate
{
    /** @var string */
    public $name = 'Accident/ Injury Form';

    /**
     * Run the seeder.
     */
    public function run()
    {
        FormTemplate::query()
            ->where(['name' => $this->name()])
            ->update([
                'version_number' => DB::raw('version_number + 1'),
                'definition' => $this->definition()
            ]);
    }

    /**
     * Return the template definition.
     */
    public function definition(): array
    {
        return [
            [
                "id" => "0_override_date_input",
                "db_id" => 4599,
                "field_id" => 14,
                "field_type" => "override_date_input",
                "field_type_name" => "Override Date Input",
                "component" => "OverrideDateInput",
                "keywords" => "Date",
                "description" => "Record of Accident",
                "instructions" => "Please provide the accurate date of the accident",
                "has_min_max_fields" => 1,
                "has_mandatory_field" => 0,
                "is_min_max_date" => 1,
                "attributes" => ["name" => "Date", "value" => null, "required" => true],
            ],
            [
                "id" => "6_largetext",
                "db_id" => 4605,
                "field_id" => 9,
                "field_type" => "largetext",
                "field_type_name" => "Multi Line Text Input",
                "component" => "Largetext",
                "keywords" => "body, injury, other",
                "description" => "Other injuries received",
                "instructions" => "Please provide details of injury",
                "has_min_max_fields" => 1,
                "has_mandatory_field" => 1,
                "is_min_max_date" => 0,
                "attributes" => [
                    "name" => "Please provide full details",
                    "value" => "Other",
                    "min" => null,
                    "max" => null,
                ],
                "options" => [
                    [
                        "id" => 7102,
                        "form_field_id" => 4605,
                        "triggered_task_id" => null,
                        "name" => "Other",
                        "trigger_has_date" => 0,
                        "created_at" => "2020-03-24 21:21:02",
                        "updated_at" => "2020-03-24 21:21:02",
                        "fv_form_field_option_id" => null,
                        "triggered_task" => null,
                    ],
                ],
            ],
            [
                "id" => "7_image_editor",
                "db_id" => 4606,
                "field_id" => 12,
                "field_type" => "image_editor",
                "field_type_name" => "Image Editor",
                "component" => "ImageEditor",
                "keywords" => null,
                "description" => null,
                "instructions" => null,
                "has_min_max_fields" => 0,
                "has_mandatory_field" => 0,
                "is_min_max_date" => 0,
                "attributes" => [
                    "name" => "Please mark area of injury",
                    "value" => [
                        [
                            "fileID" => $this->asset('body-map.png') ? $this->asset('body-map.png')->id : null,
                            "fileName" => $this->asset('body-map.png') ? $this->asset('body-map.png')->name : null,
                            "fileUrl" => $this->asset('body-map.png') ? $this->asset('body-map.png')->system_name : null,
                        ]
                    ],
                ],
                "isFileField" => true,
                "isFileSavable" => false,
				...
				...
				...
            ],
        ];
    }

    private function asset(string $name): SharedAsset
    {
        return SharedAsset::where('name', $name)->first();
    }
}

With this, we'll be easily able to jump in and change what we need, then re-seed the data. The drawback of the above is then having to have a separate class for each template; at present we have over 114.

Are there any better solutions here?

0 likes
0 replies

Please or to participate in this conversation.