awsmug/torro-forms

View on GitHub
src/components/legacy-upgrades.php

Summary

Maintainability
F
6 days
Test Coverage
<?php
/**
 * Legacy upgrades class
 *
 * @package TorroForms
 * @since 1.0.0
 */

namespace awsmug\Torro_Forms\Components;

use Leaves_And_Love\Plugin_Lib\Service;

/**
 * Class for upgrading from legacy versions.
 *
 * @since 1.0.0
 */
class Legacy_Upgrades extends Service {

    /**
     * Constructor.
     *
     * @since 1.0.0
     *
     * @param string $prefix Instance prefix.
     */
    public function __construct( $prefix ) {
        $this->set_prefix( $prefix );
    }

    /**
     * Upgrades legacy settings to new schema.
     *
     * @since 1.0.0
     */
    public function upgrade_legacy_settings() {
        $prefix = $this->get_prefix();

        $general_mappings = array(
            'modules'        => array( $prefix . 'settings_general_modules', 'modules' ),
            'slug'           => array( $prefix . 'settings_general_slug', 'string' ),
            'frontend_css'   => array( $prefix . 'settings_general_frontend_css', 'bool' ),
            'hard_uninstall' => array( $prefix . 'settings_general_hard_uninstall', 'bool' ),
        );

        $general = get_option( $prefix . 'general_settings', array() );

        foreach ( $general_mappings as $option => $mapping_data ) {
            // New values already set take precedence.
            if ( isset( $general[ $option ] ) ) {
                continue;
            }

            $old = get_option( $mapping_data[0] );
            if ( false === $old ) {
                continue;
            }

            switch ( $mapping_data[1] ) {
                case 'bool':
                    $new = ! empty( $old ) && 'no' !== strtolower( $old ) ? true : false;
                    break;
                case 'modules':
                    $old = (array) $old;
                    $new = array();
                    if ( in_array( 'actions', $old, true ) ) {
                        $new[] = 'actions';
                    }
                    if ( in_array( 'results', $old, true ) ) {
                        $new[] = 'evaluators';
                    }
                    if ( in_array( 'form-settings', $old, true ) ) {
                        $new[] = 'form_settings';
                        $new[] = 'access_controls';
                        $new[] = 'protectors';
                    }
                    break;
                case 'string':
                default:
                    $new = $old;
            }

            $general[ $option ] = $new;
        }

        if ( ! empty( $general ) ) {
            update_option( $prefix . 'general_settings', $general );
        }

        $mappings = array(
            'access_controls' => array(
                'members' => array(
                    'invitation_from_name'      => array( $prefix . 'settings_visitors_selectedmembers_invite_from_name', 'string' ),
                    'invitation_from_email'     => array( $prefix . 'settings_visitors_selectedmembers_invite_from', 'string' ),
                    'invitation_from_subject'   => array( $prefix . 'settings_visitors_selectedmembers_invite_from_subject', 'string' ),
                    'invitation_from_message'   => array( $prefix . 'settings_visitors_selectedmembers_invite_from_text', 'string' ),
                    'reinvitation_from_name'    => array( $prefix . 'settings_visitors_selectedmembers_reinvite_from_name', 'string' ),
                    'reinvitation_from_email'   => array( $prefix . 'settings_visitors_selectedmembers_reinvite_from', 'string' ),
                    'reinvitation_from_subject' => array( $prefix . 'settings_visitors_selectedmembers_reinvite_from_subject', 'string' ),
                    'reinvitation_from_message' => array( $prefix . 'settings_visitors_selectedmembers_reinvite_from_text', 'string' ),
                ),
            ),
            'protectors'      => array(
                'recaptcha' => array(
                    'site_key'   => array( $prefix . 'settings_form_settings_spam_protection_recaptcha_sitekey', 'string' ),
                    'secret_key' => array( $prefix . 'settings_form_settings_spam_protection_recaptcha_secret', 'string' ),
                ),
            ),
        );

        foreach ( $mappings as $module => $module_mappings ) {
            $settings = get_option( $prefix . 'module_' . $module, array() );

            foreach ( $module_mappings as $submodule => $submodule_mappings ) {
                $option_prefix = ! empty( $submodule ) ? $submodule . '__' : '';

                foreach ( $submodule_mappings as $option => $mapping_data ) {
                    // New values already set take precedence.
                    if ( isset( $settings[ $option_prefix . $option ] ) ) {
                        continue;
                    }

                    $old = get_option( $mapping_data[0] );
                    if ( false === $old ) {
                        continue;
                    }

                    switch ( $mapping_data[1] ) {
                        case 'string':
                        default:
                            $new = $old;
                    }

                    $settings[ $option_prefix . $option ] = $new;
                }
            }

            if ( ! empty( $settings ) ) {
                update_option( $prefix . 'module_' . $module, $settings );
            }
        }
    }

    /**
     * Upgrades legacy form metadata to new schema.
     *
     * @since 1.0.0
     *
     * @global \wpdb $wpdb WordPress database abstraction object.
     *
     * @param int $form_id ID of the form for which to migrate data.
     */
    public function upgrade_legacy_form_meta( $form_id ) {
        global $wpdb;

        $prefix = $this->get_prefix();

        $participants = $this->get_full_table_name( 'participants' );
        $email_notifications = $this->get_full_table_name( 'email_notifications' );

        $mappings = array(
            'access_controls' => array(
                'user_identification' => array(
                    'prevent_multiple_submissions' => array( array( 'form_access_controls_allmembers_same_users', 'form_access_controls_selectedmembers_same_users' ), 'bool' ),
                    'identification_modes'         => array(
                        'ip_address' => 'form_access_controls_check_ip',
                        'cookie'     => 'form_access_controls_check_cookie',
                    ),
                    'already_submitted_message'    => array( 'already_entered_text', 'string' ),
                ),
                'members'               => array(
                    'allowed_users'          => 'PARTICIPANTS',
                    'login_required_message' => array( 'to_be_logged_in_text', 'string' ),
                ),
                'timerange'             => array(
                    'start' => array( 'start_date', 'datetime' ),
                    'end'   => array( 'end_date', 'datetime' ),
                ),
            ),
            'actions'         => array(
                'email_notifications' => array(
                    'notifications' => 'EMAIL_NOTIFICATIONS',
                ),
                'redirection'         => array(
                    'type' => array( 'redirect_type', 'string' ),
                    'page' => array( 'redirect_page', 'string' ),
                    'url'  => array( 'redirect_url', 'string' ),
                ),
            ),
            'evaluators'      => array(),
            'form_settings'   => array(
                '' => array(
                    'show_container_title'  => array( 'show_page_title', 'bool' ),
                    'previous_button_label' => array( 'previous_button_text', 'string' ),
                    'next_button_label'     => array( 'next_button_text', 'string' ),
                    'submit_button_label'   => array( 'send_button_text', 'string' ),
                    'success_message'       => array( 'redirect_text_content', 'string' ),
                    'allow_get_params'      => array( 'allow_get_param', 'bool' ),
                ),
            ),
            'protectors'      => array(
                'honeypot'  => array(
                    'enabled' => array( 'honeypot_enabled', 'bool' ),
                ),
                'linkcount' => array(
                    'enabled' => array( 'linkcount_enabled', 'bool' ),
                ),
                'recaptcha' => array(
                    'enabled' => array( 'recaptcha_enabled', 'bool' ),
                    'type'    => array( 'recaptcha_type', 'string' ),
                    'size'    => array( 'recaptcha_size', 'string' ),
                    'theme'   => array( 'recaptcha_theme', 'string' ),
                ),
                'timetrap'  => array(
                    'enabled' => array( 'timetrap_enabled', 'bool' ),
                ),
            ),
        );

        $skip_enabled = array(
            'access_controls-user_identification',
            'access_controls-timerange',
            'actions-email_notifications',
            'actions-redirection',
            'protectors-honeypot',
            'protectors-linkcount',
            'protectors-recaptcha',
            'protectors-timetrap',
        );

        foreach ( $mappings as $module => $module_mappings ) {
            $metadata = get_post_meta( $form_id, $prefix . 'module_' . $module, true );
            if ( ! is_array( $metadata ) ) {
                $metadata = array();
            }

            foreach ( $module_mappings as $submodule => $submodule_mappings ) {
                $submodule_data_found = false;

                $form_option_prefix = ! empty( $submodule ) ? $submodule . '__' : '';

                foreach ( $submodule_mappings as $form_option => $mapping_data ) {
                    if ( 'PARTICIPANTS' === $mapping_data ) {
                        if ( get_option( $prefix . 'legacy_participants_table_installed' ) === 'true' ) {
                            $user_ids = $wpdb->get_col( $wpdb->prepare( "SELECT DISTINCT user_id FROM $participants WHERE form_id = %d", $form_id ) );
                            if ( ! empty( $user_ids ) ) {
                                $submodule_data_found = true;

                                // New values already set take precedence.
                                if ( ! isset( $metadata[ $form_option_prefix . $form_option ] ) ) {
                                    $metadata[ $form_option_prefix . $form_option ] = $user_ids;
                                }
                            }
                        }
                        continue;
                    }

                    if ( 'EMAIL_NOTIFICATIONS' === $mapping_data ) {
                        if ( get_option( $prefix . 'legacy_email_notifications_table_installed' ) === 'true' ) {
                            $notifications = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $email_notifications WHERE form_id = %d", $form_id ) );
                            if ( ! empty( $notifications ) ) {
                                $submodule_data_found = true;

                                // New values already set take precedence.
                                if ( ! isset( $metadata[ $form_option_prefix . $form_option ] ) ) {
                                    $metadata[ $form_option_prefix . $form_option ] = array();
                                    foreach ( $notifications as $notification ) {
                                        $metadata[ $form_option_prefix . $form_option ][] = array(
                                            'from_name'   => $notification->from_name,
                                            'from_email'  => $notification->from_email,
                                            'reply_email' => $notification->reply_email,
                                            'to_email'    => $notification->to_email,
                                            'subject'     => $notification->subject,
                                            'message'     => wpautop( $notification->message ),
                                        );
                                    }
                                }
                            }
                        }
                        continue;
                    }

                    if ( ! isset( $mapping_data[0] ) ) {
                        $new = array();
                        foreach ( $mapping_data as $group_value => $old_form_option ) {
                            $old = get_post_meta( $form_id, $old_form_option, true );
                            if ( ! empty( $old ) && 'no' !== strtolower( $old ) ) {
                                $new[] = $group_value;
                            }
                        }

                        $metadata[ $form_option_prefix . $form_option ] = $new;
                        continue;
                    }

                    $old = array();
                    if ( is_array( $mapping_data[0] ) ) {
                        foreach ( $mapping_data[0] as $old_form_option ) {
                            $old = get_post_meta( $form_id, $old_form_option );
                            if ( ! empty( $old ) ) {
                                break;
                            }
                        }
                    } else {
                        $old = get_post_meta( $form_id, $mapping_data[0] );
                    }

                    if ( empty( $old ) ) {
                        continue;
                    }

                    $submodule_data_found = true;

                    // New values already set take precedence.
                    if ( isset( $metadata[ $form_option_prefix . $form_option ] ) ) {
                        continue;
                    }

                    $old = $old[0];

                    switch ( $mapping_data[1] ) {
                        case 'bool':
                            $new = ! empty( $old ) && 'no' !== strtolower( $old ) ? true : false;
                            break;
                        case 'datetime':
                            if ( ! is_numeric( $old ) ) {
                                $old = strtotime( $old );
                            }
                            $new = date( 'Y-m-d H:i:s', $old );
                            break;
                        case 'string':
                        default:
                            $new = $old;
                    }

                    $metadata[ $form_option_prefix . $form_option ] = $new;
                }

                if ( ! empty( $form_option_prefix ) && ! in_array( $module . '-' . $submodule, $skip_enabled, true ) && $submodule_data_found ) {
                    $metadata[ $form_option_prefix . 'enabled' ] = true;
                }
            }

            if ( ! empty( $metadata ) ) {
                update_post_meta( $form_id, $prefix . 'module_' . $module, $metadata );
            }
        }
    }

    /**
     * Upgrades legacy form metadata to new schema if necessary.
     *
     * @since 1.0.0
     *
     * @param int $form_id ID of the form for which to migrate data.
     * @return bool True if form metadata was migrated, false if it had already been
     *              migrated before.
     */
    public function maybe_upgrade_legacy_form_meta( $form_id ) {
        if ( get_post_meta( $form_id, $this->get_prefix() . 'legacy_needs_migration', true ) !== 'true' ) {
            return false;
        }

        $this->upgrade_legacy_form_meta( $form_id );

        delete_post_meta( $form_id, $this->get_prefix() . 'legacy_needs_migration' );

        return true;
    }

    /**
     * Upgrades legacy form attachment statuses to new attachment taxonomy term if necessary.
     *
     * This method will migrate a maximum of 50 attachments at a time, so it may not necessarily
     * perform the full migration. It will only delete the flag once the last attachment has been
     * migrated.
     *
     * @since 1.0.0
     *
     * @global \wpdb $wpdb WordPress database abstraction object.
     *
     * @return bool True if form attachments were migrated, false if they had already been
     *              migrated before.
     */
    public function maybe_upgrade_legacy_form_attachment_statuses() {
        global $wpdb;

        if ( get_option( $this->get_prefix() . 'legacy_attachments_need_migration' ) !== 'true' ) {
            return false;
        }

        $general = get_option( $this->get_prefix() . 'general_settings', array() );

        // If no term is set, migration is not possible.
        if ( empty( $general['attachment_taxonomy_term_id'] ) ) {
            return true;
        }

        $taxonomy_slug = torro()->taxonomies()->get_attachment_taxonomy_slug();

        // If no taxonomy is available, migration is not possible.
        if ( empty( $taxonomy_slug ) ) {
            return true;
        }

        $form_attachment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = %s AND post_status = %s LIMIT 50", 'attachment', 'torro-forms-upload' ) );
        foreach ( $form_attachment_ids as $form_attachment_id ) {
            $result = wp_set_post_terms( $form_attachment_id, array( $general['attachment_taxonomy_term_id'] ), $taxonomy_slug, true );
            if ( is_array( $result ) ) {
                wp_update_post( array(
                    'ID'          => $form_attachment_id,
                    'post_status' => 'inherit',
                ) );
            }
        }

        $form_attachment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = %s AND post_status = %s LIMIT 1", 'attachment', 'torro-forms-upload' ) );
        if ( empty( $form_attachment_ids ) ) {
            delete_option( $this->get_prefix() . 'legacy_attachments_need_migration' );
        }

        return true;
    }

    /**
     * Runs the upgrade from a legacy version.
     *
     * @since 1.0.0
     *
     * @param string $legacy_db_version The legacy version number.
     *
     * @codeCoverageIgnore
     */
    public function upgrade( $legacy_db_version ) {
        $last_legacy_db_version = '1.0.10';

        if ( $legacy_db_version === $last_legacy_db_version ) {
            return;
        }

        require_once ABSPATH . 'wp-admin/includes/upgrade.php';

        if ( version_compare( $legacy_db_version, '1.0.3', '<' ) ) {
            $this->upgrade_to_1_0_3();
            $this->update_db_version( '1.0.3' );
        }

        if ( version_compare( $legacy_db_version, '1.0.4', '<' ) ) {
            $this->upgrade_to_1_0_4();
            $this->update_db_version( '1.0.4' );
        }

        if ( version_compare( $legacy_db_version, '1.0.5', '<' ) ) {
            $this->upgrade_to_1_0_5();
            $this->update_db_version( '1.0.5' );
        }

        if ( version_compare( $legacy_db_version, '1.0.6', '<' ) ) {
            $this->upgrade_to_1_0_6();
            $this->update_db_version( '1.0.6' );
        }

        if ( version_compare( $legacy_db_version, '1.0.7', '<' ) ) {
            $this->upgrade_to_1_0_7();
            $this->update_db_version( '1.0.7' );
        }

        if ( version_compare( $legacy_db_version, '1.0.8', '<' ) ) {
            $this->upgrade_to_1_0_8();
            $this->update_db_version( '1.0.8' );
        }

        if ( version_compare( $legacy_db_version, '1.0.9', '<' ) ) {
            $this->upgrade_to_1_0_9();
            $this->update_db_version( '1.0.9' );
        }

        if ( version_compare( $legacy_db_version, '1.0.10', '<' ) ) {
            $this->upgrade_to_1_0_10();
            $this->update_db_version( '1.0.10' );
        }
    }

    /**
     * Upgrades to legacy version 1.0.3.
     *
     * @since 1.0.0
     *
     * @global \wpdb $wpdb WordPress database abstraction object.
     *
     * @codeCoverageIgnore
     */
    protected function upgrade_to_1_0_3() {
        global $wpdb;

        $elements = $this->get_full_table_name( 'elements' );

        $wpdb->query( "UPDATE $elements SET type='textfield' WHERE type='Text'" );
    }

    /**
     * Upgrades to legacy version 1.0.4.
     *
     * @since 1.0.0
     *
     * @global \wpdb $wpdb WordPress database abstraction object.
     *
     * @codeCoverageIgnore
     */
    protected function upgrade_to_1_0_4() {
        global $wpdb;

        $containers = $this->get_full_table_name( 'containers' );
        $elements = $this->get_full_table_name( 'elements' );
        $charset_collate = $wpdb->get_charset_collate();

        $sql = "CREATE TABLE $containers (
            id int(11) NOT NULL AUTO_INCREMENT,
            form_id int(11) NOT NULL,
            label text NOT NULL,
            sort int(11) NOT NULL,
            UNIQUE KEY id (id)
            ) ENGINE = INNODB " . $charset_collate . ";";

        dbDelta( $sql );

        $wpdb->query( "ALTER TABLE $elements ADD container_id INT(11) NOT NULL AFTER form_id" );
    }

    /**
     * Upgrades to legacy version 1.0.5.
     *
     * @since 1.0.0
     *
     * @global \wpdb $wpdb WordPress database abstraction object.
     *
     * @codeCoverageIgnore
     */
    protected function upgrade_to_1_0_5() {
        global $wpdb;

        $element_settings = $this->get_full_table_name( 'element_settings' );
        $settings = $this->get_full_table_name( 'settings' );

        $wpdb->query( "ALTER TABLE $settings RENAME TO $element_settings" );
    }

    /**
     * Upgrades to legacy version 1.0.6.
     *
     * @since 1.0.0
     *
     * @global \wpdb $wpdb WordPress database abstraction object.
     *
     * @codeCoverageIgnore
     */
    protected function upgrade_to_1_0_6() {
        global $wpdb;

        $wpdb->update( $wpdb->posts, array(
            'post_type'    => $this->get_prefix() . 'form',
        ), array(
            'post_type'    => 'torro-forms',
        ), array( '%s' ), array( '%s' ) );

        $wpdb->update( $wpdb->term_taxonomy, array(
            'taxonomy'    => $this->get_prefix() . 'form_category',
        ), array(
            'taxonomy'    => 'torro-forms-categories',
        ), array( '%s' ), array( '%s' ) );
    }

    /**
     * Upgrades to legacy version 1.0.7.
     *
     * @since 1.0.0
     *
     * @global \wpdb $wpdb WordPress database abstraction object.
     *
     * @codeCoverageIgnore
     */
    protected function upgrade_to_1_0_7() {
        global $wpdb;

        $elements = $this->get_full_table_name( 'elements' );

        $wpdb->query( "ALTER TABLE $elements DROP form_id" );
    }

    /**
     * Upgrades to legacy version 1.0.8.
     *
     * @since 1.0.0
     *
     * @global \wpdb $wpdb WordPress database abstraction object.
     *
     * @codeCoverageIgnore
     */
    protected function upgrade_to_1_0_8() {
        global $wpdb;

        $email_notifications = $this->get_full_table_name( 'email_notifications' );

        $wpdb->query( "ALTER TABLE $email_notifications ADD reply_email TEXT NOT NULL AFTER from_email" );
    }

    /**
     * Upgrades to legacy version 1.0.9.
     *
     * @since 1.0.0
     *
     * @global \wpdb $wpdb WordPress database abstraction object.
     *
     * @codeCoverageIgnore
     */
    protected function upgrade_to_1_0_9() {
        global $wpdb;

        $elements = $this->get_full_table_name( 'elements' );

        $wpdb->update(
            $elements,
            array(
                'label' => '<hr />',
                'type'  => 'content'
            ),
            array(
                'type'  => 'separator'
            )
        );
    }

    /**
     * Upgrades to legacy version 1.0.10.
     *
     * @since 1.0.0
     *
     * @global \wpdb $wpdb WordPress database abstraction object.
     */
    protected function upgrade_to_1_0_10() {
        global $wpdb;

        $containers          = $this->get_full_table_name( 'containers' );
        $elements            = $this->get_full_table_name( 'elements' );
        $element_answers     = $this->get_full_table_name( 'element_answers' );
        $element_choices     = $this->get_full_table_name( 'element_choices' );
        $element_settings    = $this->get_full_table_name( 'element_settings' );
        $results             = $this->get_full_table_name( 'results' );
        $submissions         = $this->get_full_table_name( 'submissions' );
        $result_values       = $this->get_full_table_name( 'result_values' );
        $submission_values   = $this->get_full_table_name( 'submission_values' );
        $participants        = $this->get_full_table_name( 'participants' );
        $email_notifications = $this->get_full_table_name( 'email_notifications' );

        $wpdb->query( "ALTER TABLE $containers CHANGE sort sort int(11) unsigned NOT NULL default '0'" );
        $wpdb->query( "ALTER TABLE $containers ADD KEY form_id (form_id)" );
        $wpdb->query( "ALTER TABLE $elements CHANGE sort sort int(11) unsigned NOT NULL default '0'" );
        $wpdb->query( "ALTER TABLE $elements ADD KEY container_id (container_id)" );
        $wpdb->query( "ALTER TABLE $elements ADD KEY type (type)" );
        $wpdb->query( "ALTER TABLE $elements ADD KEY type_container_id (type,container_id)" );
        $wpdb->query( "ALTER TABLE $element_answers RENAME TO $element_choices" );
        $wpdb->query( "ALTER TABLE $element_choices CHANGE answer value text NOT NULL" );
        $wpdb->query( "ALTER TABLE $element_choices CHANGE sort sort int(11) unsigned NOT NULL default '0'" );
        $wpdb->query( "ALTER TABLE $element_choices ADD field char(100) NOT NULL default '_main' AFTER element_id" );
        $wpdb->query( "ALTER TABLE $element_choices ADD KEY element_id (element_id)" );
        $wpdb->query( "ALTER TABLE $element_settings ADD KEY element_id (element_id)" );
        $wpdb->query( "ALTER TABLE $results RENAME TO $submissions" );
        $wpdb->query( "ALTER TABLE $submissions CHANGE remote_addr remote_addr char(50) NOT NULL" );
        $wpdb->query( "ALTER TABLE $submissions CHANGE cookie_key user_key char(50) NOT NULL" );
        $wpdb->query( "ALTER TABLE $submissions ADD status char(50) NOT NULL default 'completed' AFTER user_key" );
        $wpdb->query( "ALTER TABLE $submissions ADD KEY form_id (form_id)" );
        $wpdb->query( "ALTER TABLE $submissions ADD KEY user_id (user_id)" );
        $wpdb->query( "ALTER TABLE $submissions ADD KEY status (status)" );
        $wpdb->query( "ALTER TABLE $submissions ADD KEY status_form_id (status,form_id)" );
        $wpdb->query( "ALTER TABLE $result_values RENAME TO $submission_values" );
        $wpdb->query( "ALTER TABLE $submission_values CHANGE result_id submission_id int(11) unsigned NOT NULL" );
        $wpdb->query( "ALTER TABLE $submission_values ADD field char(100) NOT NULL default '' AFTER element_id" );
        $wpdb->query( "ALTER TABLE $submission_values ADD KEY submission_id (submission_id)" );
        $wpdb->query( "ALTER TABLE $submission_values ADD KEY element_id (element_id)" );

        $this->upgrade_legacy_settings();

        $form_attachment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = %s AND post_status = %s LIMIT 1", 'attachment', 'torro-forms-upload' ) );
        if ( ! empty( $form_attachment_ids ) ) {
            // Set a flag to indicate that some form attachments need to have their old status migrated to a taxonomy term.
            update_option( $this->get_prefix() . 'legacy_attachments_need_migration', 'true' );
        }

        // Set a flag that the old participants table still exists.
        update_option( $this->get_prefix() . 'legacy_participants_table_installed', 'true' );

        // Set a flag that the old email notifications table still exists.
        update_option( $this->get_prefix() . 'legacy_email_notifications_table_installed', 'true' );

        // If forms exist, their data needs to be migrated on-the-fly later.
        $form_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = %s", $this->get_prefix() . 'form' ) );
        if ( empty( $form_ids ) ) {
            return;
        }

        // Set flags to indicate that form meta still need to be migrated.
        $insert_flags = array();
        foreach ( $form_ids as $form_id ) {
            $insert_flags[] = $wpdb->prepare( "( %d, %s, %s)", (int) $form_id, $this->get_prefix() . 'legacy_needs_migration', 'true' );
        }
        $wpdb->query( "INSERT INTO $wpdb->postmeta ( post_id, meta_key, meta_value ) VALUES " . implode( ', ', $insert_flags ) );
        foreach ( $form_ids as $form_id ) {
            wp_cache_delete( (int) $form_id, 'post_meta' );
        }
    }

    /**
     * Updates the legacy version number.
     *
     * @since 1.0.0
     *
     * @param string $legacy_db_version The legacy version number to set.
     */
    protected function update_db_version( $legacy_db_version ) {
        update_option( $this->get_prefix() . 'db_version', $legacy_db_version );
    }

    /**
     * Creates a full database table name for an unprefixed table name.
     *
     * @since 1.0.0
     *
     * @global \wpdb $wpdb WordPress database abstraction object.
     *
     * @param string $table_name Unprefixed table name.
     * @return string Full table name.
     */
    protected function get_full_table_name( $table_name ) {
        global $wpdb;

        return $wpdb->prefix . $this->get_prefix() . $table_name;
    }
}