public static function export_customfields_data(approved_contextlist $contextlist, string $component, string $area,
                string $itemidstest = 'IS NOT NULL', string $instanceidstest = 'IS NOT NULL', array $params = [],
                array $subcontext = null) {
        global $DB;

        // This query is very similar to api::get_instances_fields_data() but also works for multiple itemids
        // and has a context filter.
        list($contextidstest, $contextparams) = $DB->get_in_or_equal($contextlist->get_contextids(), SQL_PARAMS_NAMED, 'cfctx');
        $sql = "SELECT d.*, f.type AS fieldtype, f.name as fieldname, f.shortname as fieldshortname, c.itemid
            FROM {customfield_category} c
            JOIN {customfield_field} f ON f.categoryid = c.id
            JOIN {customfield_data} d ON d.fieldid = f.id AND d.instanceid $instanceidstest AND d.contextid $contextidstest
            WHERE c.component = :cfcomponent AND c.area = :cfarea AND c.itemid $itemidstest
            ORDER BY c.itemid, c.sortorder, f.sortorder";
        $params = self::get_params($component, $area, $params) + $contextparams;
        $records = $DB->get_recordset_sql($sql, $params);

        if ($subcontext === null) {
            $subcontext = [get_string('customfielddata', 'core_customfield')];
        }

        /** @var handler $handler */
        $handler = null;
        $fields = null;
        foreach ($records as $record) {
            if (!$handler || $handler->get_itemid() != $record->itemid) {
                $handler = handler::get_handler($component, $area, $record->itemid);
                $fields = $handler->get_fields();
            }
            $field = (object)['type' => $record->fieldtype, 'shortname' => $record->fieldshortname, 'name' => $record->fieldname];
            unset($record->itemid, $record->fieldtype, $record->fieldshortname, $record->fieldname);
            try {
                $field = array_key_exists($record->fieldid, $fields) ? $fields[$record->fieldid] : null;
                $data = data_controller::create(0, $record, $field);
                self::export_customfield_data($data, array_merge($subcontext, [$record->id]));
            } catch (Exception $e) {
                // We store some data that we can not initialise controller for. We still need to export it.
                self::export_customfield_data_unknown($record, $field, array_merge($subcontext, [$record->id]));
            }
        }
        $records->close();
    }