Index

MigrateTask

MMO\admin\tasks · 1 symbol · generated 5 Oct 2026

class

MigrateTask

MigrateTask.php:32

Apply the database patches a target has not run yet -- exactly once each, in order.

class MMO\admin\tasks\MigrateTask extends MMO\admin\classes\aDatabaseTask
Namespace
MMO\admin\tasks
Extends
aDatabaseTask
Idempotence comes from the journal, not from arithmetic. The old script decided what to apply by comparing the patch's filename version with the client's manifest version, which meant a patch could silently run twice (or never), and offered a `--force all patches` escape hatch to paper over it. Here a patch is applied if, and only if, its id is absent from [`Journal::getAppliedPatches`](https://mcp.mmoframework.fr/documentation/mmo.admin/php/helpers/Journal.md#journal-getappliedpatches) -- a record of what genuinely ran on that machine. A patch is a file in [`$folder`](https://mcp.mmoframework.fr/documentation/mmo.admin/php/tasks/MigrateTask.md#migratetask-folder); its id is its filename. They are applied in natural version order, so `1.2.0.js` runs before `1.10.0.js`. **It is reversible.** This task runs BEFORE [`ActivateTask`](https://mcp.mmoframework.fr/documentation/mmo.admin/php/tasks/ActivateTask.md#activatetask), so a release whose health check fails is rolled back with the database already migrated -- which used to leave the old code running against the new schema, silently, with no indication in the journal that the two no longer matched. [`rollback`](https://mcp.mmoframework.fr/documentation/mmo.admin/php/tasks/MigrateTask.md#migratetask-rollback) now puts the pre-migration snapshot back, and is [`isRollbackCritical`](https://mcp.mmoframework.fr/documentation/mmo.admin/php/tasks/MigrateTask.md#migratetask-isrollbackcritical) so a rollback that cannot complete stops everything and says so rather than carrying on. The cost is explicit and small: any write made between the snapshot and the failure is lost. The window is seconds, and nothing is serving the new code yet -- which is precisely why the migration happens before the swap rather than after it. Patches should still be written to be backward-compatible with the release they replace (expand, then contract in a later release): that is the only thing that makes a rollback free rather than merely possible.

Index

folder
pattern
snapshot
apply($context)
getDescription()
getPending($context, $excludeApplied)
isNeeded($context)
isRollbackCritical()A database left half-migrated is the one failure nobody should discover from a user's bug report.
plan($context)
rollback($context)Put the database back where it was before the first patch ran.
verify($context)
__construct($folder, $pattern, $snapshot)

Properties3

folder

protected string $folder
Type
string

pattern

protected string $pattern
Type
string

snapshot

protected bool $snapshot
Type
bool

Methods9

getPending($context, $excludeApplied)

MigrateTask.php:128
protected function getPending(MMO\admin\helpers\Context $context, bool $excludeApplied = true): array
$contextContext
$excludeApplied = trueboolexclude the patches the journal already records.
returnsarrayid => filename, in version order.

isRollbackCritical()

MigrateTask.php:111

A database left half-migrated is the one failure nobody should discover from a user's bug report.

function isRollbackCritical(): bool
returnsbool

rollback($context)

MigrateTask.php:93

Put the database back where it was before the first patch ran.

function rollback(MMO\admin\helpers\Context $context): voidCalled by the runner when a LATER task fails -- in practice, when the post-activation health check finds the site not answering. Restoring is itself destructive, so it only ever happens against a snapshot this same run took ([`aDatabaseTask::snapshot`](https://mcp.mmoframework.fr/documentation/mmo.admin/php/classes/aDatabaseTask.md#adatabasetask-snapshot)), never against a file chosen by anything else.
$contextContext
returnsvoid

__construct($folder, $pattern, $snapshot)

MigrateTask.php:33
function __construct( string $folder = '{root}/db/patches', string $pattern = '/\\.js$/', bool $snapshot = true )
$folder = '{root}/db/patches'string
$pattern = '/\\.js$/'string
$snapshot = truebool
Inherited members (41)
ConstantsDeclared byDescription
ALERTiLogLevelAlert: Action must be taken immediately.
ALLiLogLevelMask for all
ALL_PLUSiLogLeveldebug everything
BACKTRACEiLogLevel
CRITICALiLogLevelCritical: Critical conditions.
DEBUGiLogLevelDebug: Detailed debug information.
DEEPiLogLeveldebug everything with arguments
EMERGENCYiLogLevelEmergency: System is unusable.
ERRORiLogLevelError: Runtime errors that do not require immediate action but should typically be logged and monitored.
ERROR_PLUSiLogLevelMask for all error
FATALiLogLevelMask for all fatal error
INFOiLogLevelInfo: Interesting events.
INFO_PLUSiLogLevelMask for all errors/warning/notices/info
MEMORYiLogLevelinclude backtrace object
NOTICEiLogLevelNotice: Normal but significant events.
NOTICE_PLUSiLogLevelMask for all errors/warning/notices/info
REQUIREDaDatabaseTask
TRACEiLogLevelinclude backtrace as origins
WARNINGiLogLevelWarning: Exceptional occurrences that are not errors.
WARNING_PLUSiLogLevelMask for all errors and warnings
PropertiesDeclared byDescription
verbosityaDeployTask
MethodsDeclared byDescription
alert($message, $context)aDeployTaskAction must be taken immediately.
backtraces($message, $context)aDeployTaskForce-log a message at INFO level together with a full stack trace/memory snapshot (iLogLevel::BACKTRACE), bypassing the verbosity mask entirely (any non-zero verbosity is enough to trigger it).
critical($message, $context)aDeployTaskCritical conditions. No-op if CRITICAL is currently filtered out by the verbosity mask.
debug($message, $context)aDeployTaskDetailed debug information.
debugName()aDeployTask
emergency($message, $context)aDeployTaskSystem is unusable. No-op if EMERGENCY is currently filtered out by the verbosity mask.
error($message, $context)aDeployTaskRuntime errors that do not require immediate action but should typically be logged and monitored.
getDatabase($context)aDatabaseTask
getName()aDeployTask
getRepository($context)aDatabaseTask
getShell($context)aDatabaseTask
getVerbosity()aDeployTask
info($message, $context)aDeployTaskInteresting events. No-op if INFO is currently filtered out by the verbosity mask.
isChange()aDeployTaskWhether running this task CHANGES anything.
log($level, $message, $context)aDeployTaskLogs with an arbitrary level.
notice($message, $context)aDeployTaskNormal but significant events.
setVerbosity($verb)aDeployTaskSet the current verbosity mask, replacing whatever it was before.
snapshot($context)aDatabaseTaskTake a snapshot of the target's database and record it on the context, so whatever comes next is reversible.
testVerbosity($level)aDeployTaskTest whether a given level (or set of levels) is currently enabled by this instance's verbosity mask.
warning($message, $context)aDeployTaskExceptional occurrences that are not errors.