79606664

Date: 2025-05-05 09:38:03
Score: 1
Natty:
Report link

I understand exactly what you're trying to achieve — you have a deeply nested associative array (something like a YAML-style configuration), and your goal is to flatten it into structured arrays that results in database tables. These structures include categories (with parent-child relationships) , settings (tied to categories) and values (holding defaults and linked to settings).

I've played around a little bit, so I converted this into something that is ready for database insertion with the self-generated IDs you mentioned and references. The code I provided you below recursively processes categories and nested subcategories and differentiates between categories and settings (containsSettings heuristics). It assigns incremental IDs to categories, settings and your values with preserving order.

I've created a github project for you, so you can test it/download it:
https://github.com/marktaborosi/stackoverflow-79606568

This is the result you get with this:
enter image description here

I know you're not asking for a redesign or for someone to question your approach — but I would absolutely do that if I were you. An OOP version would be more cleaner, feel free to ask if you need that.
As you can see it has a tightly coupled recursion logic.

Here is the code for it (if you just want to paste it):

// This is your pre-defined settings array
$settings = [
    'basic' => [
        'installation_type' => [
            'type' => '["single","cluster"]',
            'description' => 'bla blah',
            'readonly' => false,
            'hidden' => false,
            'trigger' => null,
            'default' => 'single'
        ],
        'db_master_host' => [
            'type' => 'ip',
            'description' => 'Database hostname or IP',
            'default' => 'localhost'
        ],
        'db_master_user' => [
            'type' => 'text',
            'description' => 'Database username',
            'default' => 'test'
        ],
        'db_master_pwd' => [
            'type' => 'secret',
            'description' => 'Database user password',
        ],
        'db_master_db' => [
            'type' => 'text',
            'description' => 'Database name',
            'default' => 'test'
        ]
    ],
    'provisioning' => [
        'snom' => [
            'snom_prov_enabled' => [
                'type' => 'switch',
                'default' => false
            ],
            'snom_m3' => [
                'snom_m3_accounts' => [
                    'type' => 'number',
                    'description' => 'bla blah',
                    'default' => '0'
                ]
            ],
            'snom_dect' => [
                'snom_dect_enabled' => [
                    'type' => 'switch',
                    'description' => 'bla blah',
                    'default' => false
                ]
            ]
        ],
        'yealink' => [
            'yealink_prov_enabled' => [
                'type' => 'switch',
                'default' => false
            ]
        ]
    ]
];

$categories = [];    // array<string, array{id: int, parent: int, name: string, order: int}>
$settingsList = [];  // array<string, array{id: int, catId: int, name: string, type: string|null, desc: string|null, readonly?: bool|null, hidden?: bool|null, trigger?: string|null, order: int}>
$values = [];        // array<string, array{id: int, setId: int, default: mixed}>

$catId = 1;
$setId = 1;
$valId = 1;

$order = 1;

/**
 * Recursively process nested config array into flat category, setting, value arrays.
 */
function processCategory(
    array $array,
    int   $parentId,
    array &$categories,
    array &$settingsList,
    array &$values,
    int   &$catId,
    int   &$setId,
    int   &$valId,
    int   &$order
): void
{
    foreach ($array as $key => $item) {
        if (is_array($item) && isAssoc($item) && containsSetting($item)) {
            $currentCatId = $catId++;
            $categories[$key] = [
                'id' => $currentCatId,
                'parent' => $parentId,
                'name' => $key,
                'order' => $order++,
            ];

            foreach ($item as $settingKey => $settingData) {
                if (is_array($settingData) && isAssoc($settingData) && containsSetting($settingData)) {
                    processCategory([$settingKey => $settingData], $currentCatId, $categories, $settingsList, $values, $catId, $setId, $valId, $order);
                } else {
                    $currentSetId = $setId++;
                    $settingsList[$settingKey] = [
                        'id' => $currentSetId,
                        'catId' => $currentCatId,
                        'name' => $settingKey,
                        'type' => $settingData['type'] ?? null,
                        'desc' => $settingData['description'] ?? null,
                        'readonly' => $settingData['readonly'] ?? null,
                        'hidden' => $settingData['hidden'] ?? null,
                        'trigger' => $settingData['trigger'] ?? null,
                        'order' => $order++,
                    ];

                    $values[$settingKey] = [
                        'id' => $valId++,
                        'setId' => $currentSetId,
                        'default' => $settingData['default'] ?? null,
                    ];
                }
            }
        }
    }
}

/**
 * Check if the array is associative.
 */
function isAssoc(array $arr): bool
{
    return array_keys($arr) !== range(0, count($arr) - 1);
}

/**
 * Determine if an array contains at least one sub-setting (based on 'type' or 'default').
 */
function containsSetting(array $arr): bool
{
    foreach ($arr as $val) {
        if (is_array($val) && (isset($val['type']) || isset($val['default']))) {
            return true;
        }
    }
    return false;
}

// Run your flattening
processCategory($settings, 0, $categories, $settingsList, $values, $catId, $setId, $valId, $order);

// Dumping the results
echo "--- Categories ---\n";
echo "<pre>";
print_r($categories);
echo "--- Settings ---\n";
print_r($settingsList);
echo "--- Values ---\n";
print_r($values);
echo "</pre>";

Let me know if this helps!

Reasons:
  • Blacklisted phrase (1): stackoverflow
  • Contains signature (1):
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (0.5):
Posted by: Mark