How to create the same group of fields in several modules?

Hello. Could you give me your advice in this scenario.

I need to create a series of fields (7) in a large number of modules. Doing it one by one using studio seems like too much work because I also have to add the fields to the editing and creation views in each module.

I’m looking for ideas to smooth this out.

I thought I could create the fields programmatically. Try something like this

<?php

global $app;

$modules = ['module1', 'module2', '...']; // $GLOBALS['moduleList']?

foreach ($modules as $module) {
    $bean = BeanFactory::getBean($module);
    $fields = $bean->getFieldDefinitions();

    // if field `field_1_c` does not exist in $fields then 
    if () {
        $dictionary[$module]['fields']['field_1_c'] = [
            'name'       => 'field_1_c',
            'vname'      => 'LBL_FIELD_1_C',
            'type'       => 'enum',
            'required'   => true,
            'default'    => '',
            'options'    => 'cstm_some_list',
            'audited' => true,
            'importable' => true
        ];
    }

    // if field `field_2_c` does not exist in $fields then 
    if () {
        $dictionary[$module]['fields']['field_2_c'] = [
            'name'       => 'field_2_c',
            'vname'      => 'LBL_FIELD_2_C',
            'type'       => 'text',
            'default'    => '',
            'required'   => false,
            'importable' => 'true',
            'reportable' => true,
            'audited'    => false,
        ];
    }
}

Place it for example in public/legacy/custom/Extension/modules/Contacts/Ext/Vardefs/custom_fields.php

And every time I Quick Repair and Rebuild add the fields if they don’t exist in each module

Another option I thought could be to create the fields in a module and replicate them by changing the name of the module in the fields_meta_data table

For example

+---------------------------+-------------------+---------------------+--------+-------+-------------+-------+---+--------+-------------+-------------------+-------+-------+----------+---------------+----------+----------+----+----+----+----+
|id                         |name               |vname                |comments|help   |custom_module|type   |len|required|default_value|date_modified      |deleted|audited|massupdate|duplicate_merge|reportable|importable|ext1|ext2|ext3|ext4|
+---------------------------+-------------------+---------------------+--------+-------+-------------+-------+---+--------+-------------+-------------------+-------+-------+----------+---------------+----------+----------+----+----+----+----+
|Accountsjjwg_maps_address_c|jjwg_maps_address_c|LBL_JJWG_MAPS_ADDRESS|Address |Address|Accounts     |varchar|255|0       |null         |2019-02-18 12:06:37|0      |1      |0         |0              |1         |true      |null|    |    |    |
+---------------------------+-------------------+---------------------+--------+-------+-------------+-------+---+--------+-------------+-------------------+-------+-------+----------+---------------+----------+----------+----+----+----+----+

Could you suggest me a solution?

Regarding adding the fields in the creation and editing views of each module, will there be any shortcut?

Greetings and thanks

Have you considered using vardef extensions?

Thanks for answering, Do you mean something like creating a file in for example at

public/legacy/custom/Extension/modules/Contacts/Ext/Vardefs/reason_for_failure_c.php

Whit a content like this

$dictionary['Contact']['fields']['reason_for_failure_c'] = [
    'name'       => 'reason_for_failure_c',
    'vname'      => 'LBL_REASON_FOR_FAILURE_C',
    'type'       => 'text',
    'default'    => '',
    'required'   => false,
    'importable' => 'true',
    'reportable' => true,
    'audited'    => false,
];

This is what i am trying at custom/Extension/modules/Contacts/Ext/Vardefs/custom_fields.php

<?php

global $app;

// List of modules
$modules = [
    'module_one',
    'module_two',
];

// Function to define a new field
function defineNewField(
    string $name,
    string $type,
    string $options = '',
    bool $required = true,
    bool $audited = true,
    bool $importable = true,
    string $dbType,
    string $studio): array
{
    return [
        'name' => $name,
        'vname' => 'LBL_' . strtoupper($name),
        'type' => $type,
        'required' => $required,
        'options' => $options,
        'audited' => $audited,
        'importable' => $importable,
        'dbType' => $dbType,
        'studio' => $studio,
    ];
}

// Definitions of new fields
$newFieldsDefinitions = [
    'date_c' => [
        'type' => 'date',
        'options' => '',
        'audited' => true,
        'importable' => true,
        'dbType' => 'date',
        'studio' => 'visible',
    ],
    'change_type_c' => [
        'type' => 'dynamicenum',
        'options' => 'tipo_cambio_list',
        'audited' => true,
        'importable' => true,
        'dbType' => 'enum',
        'studio' => 'visible',
    ],
    'justification_for_the_change_c' => [
        'type' => 'enum',
        'options' => 'justificacion_cambio_list',
        'audited' => true,
        'importable' => true,
        'dbType' => 'enum',
        'studio' => 'visible',
    ],
    'implication_c' => [
        'type' => 'enum',
        'options' => 'implicacion_list',
        'audited' => true,
        'importable' => true,
        'dbType' => 'enum',
        'studio' => 'visible',
    ],
    'reasoning_c' => [
        'type' => 'text',
        'options' => '',
        'audited' => true,
        'importable' => true,
        'dbType' => 'text',
        'studio' => 'visible',
    ],'changes_c' => [
        'type' => 'text',
        'options' => '',
        'audited' => true,
        'importable' => true,
        'dbType' => 'text',
        'studio' => 'visible',
    ]
];

foreach ($modules as $module) {
    $bean = BeanFactory::getBean($module);

    if (!$bean) {
        continue; // If unable to get the bean, move to the next module
    }

    $fields = $bean->getFieldDefinitions(); // Get the bean's current field definitions

    foreach ($newFieldsDefinitions as $fieldName => $fieldDefinition) {
        if (!array_key_exists($fieldName, $fields)) {
            // If the field does not exist in the current bean's definitions, define it and add it to the dictionary
            $dictionary[$module]['fields'][$fieldName] = defineNewField(
                $fieldName,
                $fieldDefinition['type'],
                $fieldDefinition['options'] ?? '',
                $fieldDefinition['required'] ?? false,
                $fieldDefinition['audited'] ?? true,
                $fieldDefinition['importable'] ?? true,
                $fieldDefinition['dbType'],
                $fieldDefinition['studio']
            );
        }
    }
}

But when repairing and rebuilding this logic is not invoked

Could you please provide an example

Sorry, I hadn’t noticed you were already doing vardefs extensions, since I am used to seeing just array definitions there, not code and functions.

Do you see your code appearing in

public/legacy/custom/modules/Contacts/Ext/Vardefs/

after the QR&R?

If that is not the problem, then I guess SuiteCRM is not liking the code you run inside a specific module’s extensions, but tries to access other module’s vardefs.

You might be better off simply writing your script so that it runs outside SuiteCRM completely, but adds array entries into different vardefs extension files.