public static function get_categories_with_fields(string $component, string $area, int $itemid) : array {
        global $DB;

        $categories = [];

        $options = [
                'component' => $component,
                'area'      => $area,
                'itemid'    => $itemid
        ];

        $plugins = \core\plugininfo\customfield::get_enabled_plugins();
        list($sqlfields, $params) = $DB->get_in_or_equal(array_keys($plugins), SQL_PARAMS_NAMED, 'param', true, null);

        $fields = 'f.*, ' . join(', ', array_map(function($field) {
                return "c.$field AS category_$field";
        }, array_diff(array_keys(category::properties_definition()), ['usermodified', 'timemodified'])));
        $sql = "SELECT $fields
                  FROM {customfield_category} c
             LEFT JOIN {customfield_field} f ON c.id = f.categoryid AND f.type $sqlfields
                 WHERE c.component = :component AND c.area = :area AND c.itemid = :itemid
              ORDER BY c.sortorder, f.sortorder";
        $fieldsdata = $DB->get_recordset_sql($sql, $options + $params);

        foreach ($fieldsdata as $data) {
            if (!array_key_exists($data->category_id, $categories)) {
                $categoryobj = new \stdClass();
                foreach ($data as $key => $value) {
                    if (preg_match('/^category_(.*)$/', $key, $matches)) {
                        $categoryobj->{$matches[1]} = $value;
                    }
                }
                $category = category_controller::create(0, $categoryobj);
                $categories[$categoryobj->id] = $category;
            } else {
                $category = $categories[$data->categoryid];
            }
            if ($data->id) {
                $fieldobj = new \stdClass();
                foreach ($data as $key => $value) {
                    if (!preg_match('/^category_/', $key)) {
                        $fieldobj->{$key} = $value;
                    }
                }
                $field = field_controller::create(0, $fieldobj, $category);
            }
        }
        $fieldsdata->close();

        return $categories;
    }