<?php
/**
* WCS&T to WCShipping migration states.
*
* @package Automattic\WCShipping\Migration
*/
namespace Automattic\WCShipping\Migration;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class for WCS&T to WCShipping migration states.
*/
class MigrationState {
// These are used for WCS&T to WCShipping migration. 1-11 is not applicable to WCShipping but we include the whole range for clarity.
public const NOT_STARTED = 1;
public const STARTED = 2;
public const ERROR_STARTED = 3;
public const INSTALLING = 4;
public const ERROR_INSTALLING = 5;
public const ACTIVATING = 6;
public const ERROR_ACTIVATING = 7;
public const DB_MIGRATION = 8;
public const ERROR_DB_MIGRATION = 9;
public const DEACTIVATING = 10;
public const ERROR_DEACTIVATING = 11;
public const INSTALLATION_COMPLETED = 12;
public const DATA_MIGRATION_STARTED = 13;
public const DATA_MIGRATION_COMPLETED = 14;
public const LABELS_TYPE = 'labels';
public const SETTINGS_TYPE = 'settings';
public const ALL_TYPE = 'all';
public const NO_TYPE = 'none';
/**
* Constructor.
*
* @return void
*/
public static function init(): void {
add_action( 'wcshipping_labels_migration_completed', array( __CLASS__, 'labels_migration_completed' ) );
add_action( 'wcshipping_settings_migration_completed', array( __CLASS__, 'settings_migration_completed' ) );
}
/**
* Check if the given state is valid.
*
* @param int $state The migration state.
*
* @return bool
*/
public static function is_valid_state( int $state ): bool {
return in_array(
$state,
array(
self::NOT_STARTED,
self::STARTED,
self::ERROR_STARTED,
self::INSTALLING,
self::ERROR_INSTALLING,
self::ACTIVATING,
self::ERROR_ACTIVATING,
self::DB_MIGRATION,
self::ERROR_DB_MIGRATION,
self::DEACTIVATING,
self::ERROR_DEACTIVATING,
self::INSTALLATION_COMPLETED,
self::DATA_MIGRATION_STARTED,
self::DATA_MIGRATION_COMPLETED,
),
true
);
}
/**
* Check if the given type is valid.
*
* @param string $type The migration type.
*/
public static function is_valid_type( string $type ): bool {
return in_array(
$type,
array(
self::LABELS_TYPE,
self::SETTINGS_TYPE,
self::ALL_TYPE,
self::NO_TYPE,
),
true
);
}
/**
* Set the migration state in the database.
*
* @param int $state The migration state.
* @return void
*/
public static function set_state( int $state ): void {
if ( ! self::is_valid_state( $state ) ) {
return;
}
// Once the data migration is completed, we can remove the migration required and processes to run flags.
if ( self::DATA_MIGRATION_COMPLETED === $state ) {
delete_option( 'wcst_data_migration_required' );
delete_option( 'wcst_data_migration_processes_to_run' );
}
update_option( 'wcshipping_migration_state', $state, false );
}
/**
* Get the migration state from the database.
*
* @return int|bool Current state in the DB or false if not set.
*/
public static function get_state(): int {
return get_option( 'wcshipping_migration_state' );
}
/**
* Get data migration required bool from DB.
*
* @return bool True if migration is required, false otherwise.
*/
public static function is_data_migration_required(): bool {
if ( self::NO_TYPE === self::get_data_migration_required_type() ) {
return false;
}
return (bool) self::get_data_migration_required_type();
}
/**
* Set the data migration required type in the database.
*
* @param string $type The data migration required type.
* @return void
*/
public static function set_data_migration_required_type( string $type ): void {
if ( ! self::is_valid_type( $type ) ) {
return;
}
// We have 2 types of migrations that can run async so we need to set a flag to adjust as each completes.
switch ( $type ) {
case self::LABELS_TYPE:
case self::SETTINGS_TYPE:
update_option( 'wcst_data_migration_processes_to_run', 1, false );
break;
case self::ALL_TYPE:
update_option( 'wcst_data_migration_processes_to_run', 2, false );
break;
}
update_option( 'wcst_data_migration_required', $type );
}
/**
* Get the number of data migration processes to run from the database.
*
* @return int The number data migration processes to run, -1 if nothing has been set.
*/
public static function get_data_migration_processes_to_run(): int {
return (int) get_option( 'wcst_data_migration_processes_to_run', '-1' );
}
/**
* Get the data migration required type from the database.
*
* @return string|false The data migration required type, or false if not set.
*/
public static function get_data_migration_required_type() {
return get_option( 'wcst_data_migration_required' );
}
/**
* Determine if the migration is complete and set the state accordingly.
*/
public static function maybe_mark_migration_complete(): void {
if ( self::DATA_MIGRATION_STARTED !== self::get_state() ) {
return;
}
$processes_to_run = self::get_data_migration_processes_to_run();
if ( 0 > $processes_to_run ) {
switch ( self::get_data_migration_required_type() ) {
case self::LABELS_TYPE:
case self::SETTINGS_TYPE:
$processes_to_run = 1;
break;
case self::ALL_TYPE:
$processes_to_run = 2;
break;
default:
$processes_to_run = 0;
break;
}
}
// We subtract 1 from the processes to run each time a migration completes, once it reaches 0 we can mark the migration as complete.
if ( 0 >= ( $processes_to_run - 1 ) ) {
self::set_state( self::DATA_MIGRATION_COMPLETED );
} else {
update_option( 'wcst_data_migration_processes_to_run', $processes_to_run - 1, false );
}
}
/**
* When label migration finished, decrement the processes to run and mark the migration as complete if needed.
*/
public static function labels_migration_completed(): void {
self::maybe_mark_migration_complete();
}
/**
* When settings migration finished, decrement the processes to run and mark the migration as complete if needed.
*/
public static function settings_migration_completed(): void {
self::maybe_mark_migration_complete();
}
}