ProductionController
MMO\admin\controllers · 1 symbol · generated 5 Oct 2026
ProductionController
ProductionController.php:54The command-line surface of mmo.admin: build, ship, activate, roll back, back up, restore and migrate one or more deployment targets.
- Namespace
MMO\admin\controllers- Extends
- aShellController
- See
aDeployTask, and hands both to aRunner. Every command is therefore the same three lines, and anything you can do interactively you can do from a script, identically.,$protectedTagshas to be confirmed deliberately (confirmProtected), and a fan-out across several of them deploys to the first one alone and stops for a look before continuing (runFanOut).
Index
Properties29
allowed
- Type
- array
buildCommands
- Type
- array
buildFolder
- Type
- string
buildOptions
- Type
- array
credentialsFile
dashboardCommand
exclude
- Type
- array
exitCode
- Type
- int
forbidden
- Type
- array
git
- Type
- null | Repository
healthIsFatal
- Type
- bool
healthTimeout
- Type
- int
include
- Type
- array
installTemplates
- Type
- array
manifest
patchFolder
- Type
- string
postInstall
protectedTags
- Type
- array
reports
- Type
- array
repository
- Type
- null | iRepository
requiredTools
- Type
- array
sshConfigFile
store
targets
targetsFile
- Type
- string
templateFolder
- Type
- string
versionLibraries
versionMessage
- Type
- string
versionOnRelease
- Type
- bool
Methods61
bumpVersion($part, $dryRun, $library)
ProductionController.php:786| $part = null | null | string | major, minor or patch; null: ask at a terminal, the patch otherwise. |
| $dryRun = false | bool | say what would change, change nothing. |
| $library = null | null | string | a library the project packages (null: the project). |
| returns | null | string | the new version; null when nothing was changed (a dry run, or no answer). |
| throws | when mmo.json is not committed as it is, or its version is not major.minor.patch. |
confirmProtected($route, $targets, $verb)
ProductionController.php:431Make changing a production target a deliberate act.
doctor()
ProductionController.php:566Check the files, then every server and target: what doctor prints.
| returns | void |
getExitCode()
ProductionController.php:220| returns | int | 0 when everything this invocation did succeeded, 1 otherwise. The entry script is expected to exit() with this -- templates/scripts/admin.php. |
getGit()
ProductionController.php:466| returns | Repository | @throws eRuntime when none is configured. |
getLibraryVersions($all)
ProductionController.php:840| $all = false | bool | every library packaged from a git checkout; false: those of $versionLibraries. |
| returns | array | Version> name => the version of each library the project packages from a git checkout -- a phar, or a folder that is none, has no commit to name. |
getOptions($route)
ProductionController.php:284getProjectFolder()
ProductionController.php:199| returns | string | the project: the folder holding deploy.json, where everything deploying needs is kept. |
getProjectVersion()
ProductionController.php:831| returns | Version | the project's: its mmo.json, in the repository releases are built from. |
getProtected($targets)
ProductionController.php:413getProtectedTags()
ProductionController.php:202| returns | array | the tags whose targets need a deliberate confirmation. |
getReadiness()
ProductionController.php:188| returns | Readiness | whether this project is set up to deploy, read from its files now: never cached. |
getReleaseTasks()
ProductionController.php:497The full pipeline: everything a release needs, in the only order that is safe.
| returns | array |
getReports()
ProductionController.php:223| returns | array | every per-target report of this invocation. |
getRepository()
ProductionController.php:205| returns | null | Repository | the project's repository, when one is configured. |
getRunner($route)
ProductionController.php:272getStore()
ProductionController.php:182| returns | Store | the declaration, loaded once. |
getTargets()
ProductionController.php:211| returns | Targets | the declared targets, loaded once. |
getVersionOptions($route)
ProductionController.php:959| $route | Route | |
| returns | null | array | string|null, force: bool, yes: bool}|null what prepareVersions reads of a release's options; null with --no-version. |
index($route)
ProductionController.php:538No command: the dashboard -- the project, its targets and what was deployed where, beside the actions this project can do, one key each. Until setup is done, the steps of setup are all it offers. Dashboard
mirror($targets, $quiet)
ProductionController.php:335Read the journal of each target into this machine's history (Store::HISTORY).
newActivateTask()
ProductionController.php:489| returns | ActivateTask |
newAssertTask()
ProductionController.php:477| returns | AssertArtifactTask |
newBuildTask()
ProductionController.php:473| returns | BuildTask |
newInstallTask()
ProductionController.php:481| returns | InstallTask |
newMigrateTask()
ProductionController.php:485| returns | MigrateTask |
onRoute($route)
ProductionController.php:522A command typed on the command line asks, at a terminal, what the same command asks in the dashboard.
- See
aShellController::onRoutemakes only the dashboard (no command typed) interactive, so a command typed in full never asked anything:release --targets=demoapplied its plan without "Apply this plan on [demo] ?", and a protected target was refused as if from a script -- even to someone sitting at a terminal. Whether anyone can answer is a property of the input, not of how the command was chosen: a terminal has someone at it; cron, CI and a pipe do not, are never asked anything, and so never wait for an answer that cannot come.
prepareVersions($targets, $options, $dryRun)
ProductionController.php:872Before a release: increase the version of every package with commits since its version last changed -- each library's patch, then the project's, which records the libraries with it -- so a release never names new code with an old version. A library a project version names is the code of that version, and a release of the project is told from the previous one by its name alone.
printCheck($label, $ok, $detail, $indent)
ProductionController.php:1262| $label | string | |
| $ok | null | bool | true: good. false: needs fixing. NULL: not applicable -- optional and absent. The third state matters: a project whose servers all use the ssh agent has no credentials file and needs none, and marking that with the same red circle as an unreachable server teaches people to ignore the red circles. |
| $detail = '' | string | |
| $indent = 2 | int | |
| returns | void |
printDeployment($entry)
ProductionController.php:1274| $entry | Deployment | |
| returns | void |
printSkippedVersions($skipped)
ProductionController.php:976printStatus($target)
ProductionController.php:1185What a target actually has, read from the target and compared with what the journal claims.
printStatusLine($label, $value, $ok)
ProductionController.php:1247printTargetTools($target, $shell)
ProductionController.php:658Report which of $requiredTools the target actually has.
| $target | Target | |
| $shell | ShellRunner | |
| returns | void |
printVersion($version, $part, $why)
ProductionController.php:968One line of prepareVersions: a package, its version and the next one, and why.
printWebRoot($target, $shell)
ProductionController.php:685Report the host-fixed document root, when the target declares one.
| $target | Target | |
| $shell | ShellRunner | |
| returns | void |
route_activate($route)
ProductionController.php:988route_backup($route)
ProductionController.php:1008route_build($route)
ProductionController.php:744route_cmd($route)
ProductionController.php:1047route_doctor($route)
ProductionController.php:561route_history($route)
ProductionController.php:704route_init($route)
ProductionController.php:1137route_install($route)
ProductionController.php:998route_migrate($route)
ProductionController.php:1042route_plan($route)
ProductionController.php:728route_prune($route)
ProductionController.php:1003route_release($route)
ProductionController.php:737route_restore($route)
ProductionController.php:1022route_rollback($route)
ProductionController.php:993route_setup($route)
ProductionController.php:1091Write deploy.json -- and what else deploying needs -- by answering questions: a guide as much as a form, which explains every step and shows every change before making it. SetupWizard
route_ship($route)
ProductionController.php:983route_status($route)
ProductionController.php:697route_sync($route)
ProductionController.php:717route_targets($route)
ProductionController.php:543route_version($route)
ProductionController.php:771Increase the version in the project's mmo.json -- or a library's, with --library -- and commit it: a release is named after the project's version and packages each library under its own, so new code needs a new one.
run($route, $targets, $tasks, $verb, $extra)
ProductionController.php:309Run a pipeline over a selection, with the protected-target guards, and record the outcome as this invocation's exit code.
runFanOut($route, $runner, $targets, $tasks, $options)
ProductionController.php:379Deploy to one protected target, stop, and only continue once that one is known good.
runSetup($step, $offerDoctor, $dryRun)
ProductionController.php:1106Run SetupWizard: every step, or one step and the review of what it changes.
selectTargets($route, $title, $max)
ProductionController.php:237Which targets this invocation acts on.
setDashboardCommand($command)
ProductionController.php:208Inherited members (63)
| Constants | Declared by | Description | |
|---|---|---|---|
ALERT | iLogLevel | Alert: Action must be taken immediately. | |
ALL | iLogLevel | Mask for all | |
ALL_PLUS | iLogLevel | debug everything | |
BACKTRACE | iLogLevel | ||
CRITICAL | iLogLevel | Critical: Critical conditions. | |
DEBUG | iLogLevel | Debug: Detailed debug information. | |
DEEP | iLogLevel | debug everything with arguments | |
EMERGENCY | iLogLevel | Emergency: System is unusable. | |
ERROR | iLogLevel | Error: Runtime errors that do not require immediate action but should typically be logged and monitored. | |
ERROR_PLUS | iLogLevel | Mask for all error | |
FATAL | iLogLevel | Mask for all fatal error | |
INFO | iLogLevel | Info: Interesting events. | |
INFO_PLUS | iLogLevel | Mask for all errors/warning/notices/info | |
MEMORY | iLogLevel | include backtrace object | |
NOTICE | iLogLevel | Notice: Normal but significant events. | |
NOTICE_PLUS | iLogLevel | Mask for all errors/warning/notices/info | |
TRACE | iLogLevel | include backtrace as origins | |
WARNING | iLogLevel | Warning: Exceptional occurrences that are not errors. | |
WARNING_PLUS | iLogLevel | Mask for all errors and warnings |
| Properties | Declared by | Description | |
|---|---|---|---|
interactive | aShellController | ||
verbosity | aModule |
| Methods | Declared by | Description | |
|---|---|---|---|
alert($message, $context) | aModule | Action must be taken immediately. | |
backtraces($message, $context) | aModule | Force-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). | |
callInteractiveCommand($route, $cmd) | aShellController | Invoke the method behind $cmd (looked up via InteractiveCommands), or print an "unknown command" message if $cmd doesn't match any registered interactive command. | |
Configure($config) | aModule | Merge $config into this module's configuration in the shared Configuration. | |
critical($message, $context) | aModule | Critical conditions. No-op if CRITICAL is currently filtered out by the verbosity mask. | |
debug($message, $context) | aModule | Detailed debug information. | |
debugName() | aModule | Human-readable identifier used as the default {origin} in this instance's log messages. | |
DefaultConfig() | aModule | The config a module starts from before anything loaded via Configuration is merged in. | |
emergency($message, $context) | aModule | System is unusable. No-op if EMERGENCY is currently filtered out by the verbosity mask. | |
error($message, $context) | aModule | Runtime errors that do not require immediate action but should typically be logged and monitored. | |
ExtractRoutes($config) | aController | Extract all the APIRoute from this class, regardless of the fact they are registered in the application | |
getVerbosity() | aModule | ||
hasOtherCommand($route) | aShellController | Tell if another shell controller matched a command of its own (anything but its index) for $route | |
HasRoutes() | aController | Tells if any APIRoute are registered in the application | |
info($message, $context) | aModule | Interesting events. No-op if INFO is currently filtered out by the verbosity mask. | |
Instantiate($config) | aModule | (Re)create the shared instance immediately, configured with $config merged into the class's existing config. | |
InteractiveCommands() | aShellController | Every #[InteractiveCommand(...)]-decorated method on this class, keyed by its command name. | |
IsShared() | aModule | ||
Link($method, $data) | aController | Build a Link (URL + label/icon/description/title, taken from the route's APIRoute metadata) for a registered route. | |
log($level, $message, $context) | aModule | Logs with an arbitrary level. | |
notice($message, $context) | aModule | Normal but significant events. | |
offsetExists($key) | aModule | \ArrayAccess::offsetExists -- tells whether $key is a declared property at all, regardless of whether it is currently readable/writable through array access. | |
offsetGet($key) | aModule | \ArrayAccess::offsetGet -- reads a property directly, unless it has a #[Serialize(serialize: 'methodName')] attribute, in which case that zero-argument method is called instead (e.g. | |
offsetSet($key, $value) | aModule | \ArrayAccess::offsetSet -- sets a property directly, unless it has a #[Serialize(unserialize: 'methodName')] attribute, in which case that method is called with $value instead (e.g. | |
offsetUnset($key) | aModule | \ArrayAccess::offsetUnset -- equivalent to $module[$key] = null. | |
Route($method) | aController | Get a registered APIRoute WARNING: if this class was not registered in the application, it will return null. | |
Routes() | aController | Get a list of registered APIRoutes (from this class) in the application WARNING: if this class was not registered in the application, it will return an empty array. | |
route_help($route) | aShellController | Print CLI usage for every 'SHELL'-method route on this controller: the command line to type, each argument's name/required-ness/description, and any declared usage examples. | |
serialize($path, $serializer) | aModule | \MMO\core\interfaces\iSerializable::serialize -- exports every property (via | |
setInteractive($interactive) | aShellController | ||
setVerbosity($verb) | aModule | Set the current verbosity mask, replacing whatever it was before. | |
Shared() | aModule | Get the shared instance, creating (and configuring) it on first call. | |
showInteractiveCommands() | aShellController | Print the list of available interactive commands, plus the [ENTER]/[ESC]/q hints. | |
showSplash() | aShellController | Print the application's icon/version/title/description banner. | |
testVerbosity($level) | aModule | Test whether a given level (or set of levels) is currently enabled by this instance's verbosity mask. | |
traitUnshare($serialize) | aModule | Remove the shared instance, so the next Shared() call creates a fresh one. | |
unserialize($data, $path, $instances) | aModule | \MMO\core\interfaces\iSerializable::unserialize -- merges $data onto DefaultConfig, runs it through the (possibly overridden) constructor, then applies each resulting value to its property (via | |
Unshare($serialize) | aModule | Like tSingleton::Unshare, but also disconnects this module's instance from every event it was listening to (via Event::DisconnectListeners) before dropping it. | |
Url($method, $data) | aController | Build the URL for a registered route, filling in any {placeholder} from $data. | |
warning($message, $context) | aModule | Exceptional occurrences that are not errors. | |
__construct($config) | aModule | protected constructor, so it is not possible to do new Module(...) called by the serialization process just before being injected with data. | |
__wakeup() | aController | Called automatically right after the controller's shared instance is built (aModule::unserialize): registers onRoute as a Route listener with a low priority (-10), so it… |