MMOframework
Pourquoi l'IA Playground Bibliothèques Documentation Rechercher Agence
FR EN
Index

SetupWizard

MMO\admin\helpers · 1 symbole · générée le 27 Oct 2026

class

SetupWizard

SetupWizard.php:46

php scripts/admin.php setup: the questions whose answers are a project's deployment, asked in the order deploying needs them, each one explained -- then the files those answers make, shown before they are written.

class MMO\admin\helpers\SetupWizard
Espace de noms
MMO\admin\helpers
It is a guide as much as a form. Every step says what it asks for, why it matters and what the tool does with it, so that whoever sets a project up for the first time ends up knowing how it deploys, not only holding a deploy.json. Run again on a project that has one, every question starts from what the files already say: ENTER all the way through changes nothing -- but what it found missing or disagreeing, and asked about first. What it writes, and how: - `deploy.json`, through [`JsonEditor`](https://mmoframework.fr/fr/documentation/mmo.admin/php/helpers/JsonEditor.md#jsoneditor): only the lines that change. Its comments document its keys and it is reviewed like code, so it is edited, never regenerated; a new one starts from mmo.admin's template. Every key of every server and target is written, the default of the ones nobody chose included, and each one has a comment saying what it does ([`Declaration`](https://mmoframework.fr/fr/documentation/mmo.admin/php/helpers/Declaration.md#declaration)): what a deployment does is all in plain sight. - `deploy.credentials.json`, when a server needs a secret: private (0600) from the moment it exists, and only once `.gitignore` ignores it. A secret found in deploy.json is offered a move there. - a `Host` entry of the project's `deploy.ssh.config` ([`SshConfig`](https://mmoframework.fr/fr/documentation/mmo.admin/php/helpers/SetupWizard.md#setupwizard-sshconfig)), for a server reached through an alias it does not declare yet -- copied from `~/.ssh/config` when that has one. Private and git-ignored too: everything the project needs is in the project folder, and nothing it writes is outside it. - what `init` writes and the project lacks, the `.gitignore` and `.gitattributes` rules it misses, the pre-commit hook (`core.hooksPath`), and the values of `scripts/bootstrap.php` and `scripts/apache2.conf` the answers decide ([`PhpConfigEditor`](https://mmoframework.fr/fr/documentation/mmo.admin/php/helpers/PhpConfigEditor.md#phpconfigeditor)). Nothing is written before the last step, which shows every change as a diff -- secrets masked -- and checks that deploy.json loads ([`Store`](https://mmoframework.fr/fr/documentation/mmo.admin/php/helpers/Store.md#store)) before asking. Nothing on a server is changed: reading a host key is the only connection it opens, and only when asked to. Answers are read through \MMO\core\shell's prompts, so a stream given to \MMO\core\shell\setInput() answers them as a person would: that is how it is tested.
$wizard = new SetupWizard('/var/www/acme/deploy.json', templateFolder: '/path/to/mmo.admin/templates'); $wizard->run(); // every step $wizard->run('targets'); // the targets alone, then the review

Index

CANCELLEDthe code of the eRuntime saying nobody answered: the run stops, and nothing is written.
HOST_KEYSthe kind of a host key => the file holding it on the server, whose fingerprint ssh-keygen -l prints there.
NAMEwhat a server, a project or a new target may be called: what a shell and a path take as they are.
STEPSstep => what it is about, in the order deploying needs them.
appends
bootstrap
commands
committable
credentialsData
credentialsFilename
credentialsText
data
dryRun
filename
folder
git
hosts
original
renames
secrets
settings
sshConfig
template
templateFolder
templates
vhost
webspaceRoots
written
address($row)
aliasSettings($row)
apply($changes)
ask($question, $default, $validate)
askAlias($server, $row, $was)
askAuth($row, $secrets)
askFingerprint($row)
askHost($row)
askList($question, $default, $validate)
askManaged($row)
askPort($question, $default)
askRoot($server, $row, $secrets, $local)The folder every relative path of a target on this server starts from.
askVhost($template)Make the vhost template take its paths and its server name from each target: {public}, {folder} and {host} (Target::resolveTemplate) -- one template, right for every target whatever it d…
askWebspace($row, $folder, $before, $root)What a target on a shared webspace needs that the others do not.
bootstrapFilename()
branch()
changes()Every file the answers change, in the order it is safe to write them: .gitignore before the credentials file exists, so git never sees it unignored.
checkAgent()Say whether an ssh agent is running and holds a key: agent needs both, and neither is in a file to check later.
checkAttributes()
checkCredentialsFile()
checkHook()
checkIgnored()
checkKeys()Deal, before anything else, with what would stop deploy.json from loading whatever the answers: a secret in it, and a key mmo.admin does not know.
checkRef($ref)Warn about a branch this repository does not have: the first release of the target would fail on it.
closest($key, $known)
conclude()What to do next, in order, with the commands to type.
credentialsText()
debugName()
declarationText()
defaultKey()
describeServer($row)
directive($text, $pattern, $value)
editServer($name)
editTarget($name)
entity($name, $row)
expand($path)
fingerprint($value)
freeName($prefix, $taken)
hasDatabase()
hostKeyFile($type)
ignoresNeeded()The .gitignore rules the files about to be written need and nothing gives them: a private file is never written where git would take it, whichever step made it.
ignoreText($rule)
introduce($full)
isExample($section, $name)
isHost($host)
isIgnored($file)
isUrl($url)
listServers()
listTargets()
load()
manifest()
mask($text)
missingRules($template, $have)The rules of the template a project's .gitattributes lacks.
missingTemplates()
moveSecret($path, $key, $what)
need($answer)
objectify($data)
panelPath($path, $root)
pick($question, $options, $default)
pickName($question, $names, $default)
privateFiles()
protectedTags()
readHostKey($host, $port)Read the host key a server presents, the way the deployment's own connection will check it.
readWebspaceRoot($server, $row, $secrets)
reference($path)
relative($filename)
relativePaths($paths)
relativeTo($root, $path, $default)
removeServer($name)
removeTarget($name)
renameKey($values, $old, $new)
review($changes)Show every change: what is added, removed, run -- secrets masked.
rules($text)
run($only)Ask, explain, show, write.
saveServer($old, $new, $row, $secrets)
saveTarget($old, $new, $row)
secret($question)
setting($key)
sshConfig()
step($step)
stepFiles()
stepInstall()installTemplates and postInstall: the vhost install sets up on a server of yours -- and on no other.
stepProject()
stepScripts()
stepServers()
stepTargets()
stepWrite()
templateText($file)
urlHost($url)
userSshConfig()
validate($changes)Refuse what mmo.admin would refuse: a deploy.json that does not load, a PHP file that does not parse.
valueAt($path)
webspaceRoot($server, $row, $secrets)The folder a webspace account lands in: what pwd prints there.
withoutComments($value)
write($filename, $text, $mode)Write a file beside, then move it over: a file half written is never the one read.
yes($question, $default)
__construct($filename, $credentialsFilename, $templateFolder, $git, $sshConfig, $settings, $dryRun)

Constantes4

CANCELLED

the code of the eRuntime saying nobody answered: the run stops, and nothing is written.

const CANCELLED = 499

HOST_KEYS

the kind of a host key => the file holding it on the server, whose fingerprint ssh-keygen -l prints there.

const HOST_KEYS = […3 items]

NAME

what a server, a project or a new target may be called: what a shell and a path take as they are.

const NAME = '/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/'

STEPS

step => what it is about, in the order deploying needs them.

const STEPS = […6 items]

Propriétés24

appends

protected array $appends = []
Type
array

bootstrap

protected array $bootstrap = []
Type
array

commands

protected array $commands = []
Type
array

committable

protected array $committable = []
Type
array

credentialsData

protected array $credentialsData = []
Type
array

credentialsFilename

protected ?string $credentialsFilename
Type
null | string

credentialsText

protected string $credentialsText = ''
Type
string

data

protected array $data = []
Type
array

dryRun

protected bool $dryRun
Type
bool

filename

protected string $filename
Type
string

folder

protected string $folder
Type
string

hosts

protected array $hosts = []
Type
array

original

protected string $original = ''
Type
string

renames

protected array $renames = []
Type
array

secrets

protected array $secrets = []
Type
array

settings

protected array $settings
Type
array

sshConfig

protected ?MMO\admin\helpers\SshConfig $sshConfig
Type
null | SshConfig

template

protected array $template = []
Type
array

templateFolder

protected ?string $templateFolder
Type
null | string

templates

protected array $templates = []
Type
array

vhost

protected ?string $vhost = null
Type
null | string

webspaceRoots

protected array $webspaceRoots = []
Type
array

written

protected bool $written = false
Type
bool

Méthodes97

address($row)

SetupWizard.php:1689
protected function address(array $row): array
$rowarray
retournearraystring|null, 1: int} a server's host and port, from deploy.json or from its alias.

aliasSettings($row)

SetupWizard.php:1682
protected function aliasSettings(array $row): array
$rowarray
retournearraythe deploy.ssh.config settings of a server's alias: the ones about to be added, or the file's.

askAuth($row, $secrets)

SetupWizard.php:634
protected function askAuth(array &$row, array $secrets): array
$rowarraythe server's declaration.
$secretsarraywhat the credentials file holds for it.
retournearraywhat it will hold.

askRoot($server, $row, $secrets, $local)

SetupWizard.php:796

The folder every relative path of a target on this server starts from.

protected function askRoot(string $server, array &$row, array $secrets, bool $local): voidOn a webspace the host decides it, and prints it nowhere a person can copy it reliably (IONOS has moved it between contracts): it is read where it is true, with `pwd` ([`webspaceRoot`](https://mmoframework.fr/fr/documentation/mmo.admin/php/helpers/SetupWizard.md#setupwizard-webspaceroot)), and offered.
$serverstring
$rowarraythe server's declaration, which gets its root.
$secretsarraywhat the credentials file will hold for it: how to get in, to read it.
$localboolit is this very machine: a root is optional.
retournevoid

askVhost($template)

SetupWizard.php:1213

Make the vhost template take its paths and its server name from each target: {public}, {folder} and {host} (Target::resolveTemplate) -- one template, right for every target whatever it declares -- and ask where the certificate is.

protected function askVhost(string $template): void
$templatestringthe local template, as installTemplates names it.
retournevoid

askWebspace($row, $folder, $before, $root)

SetupWizard.php:999

What a target on a shared webspace needs that the others do not.

protected function askWebspace( array &$row, string $folder, MMO\admin\entities\Target $before, ?string $root ): void
$rowarraythe target's declaration.
$folderstringits folder, absolute.
$beforeTargetwhat it was before this edit.
$rootnull | stringits server's root: how a panel names a folder.
retournevoid

changes()

SetupWizard.php:1299

Every file the answers change, in the order it is safe to write them: .gitignore before the credentials file exists, so git never sees it unignored.

protected function changes(): array
retournearrayarray{label: string, old: string, new: string, mode?: int, secret?: bool, template?: bool}> by filename.

checkAgent()

SetupWizard.php:678

Say whether an ssh agent is running and holds a key: agent needs both, and neither is in a file to check later.

protected function checkAgent(): void
retournevoid

checkKeys()

SetupWizard.php:248

Deal, before anything else, with what would stop deploy.json from loading whatever the answers: a secret in it, and a key mmo.admin does not know.

protected function checkKeys(): void
retournevoid

checkRef($ref)

SetupWizard.php:1102

Warn about a branch this repository does not have: the first release of the target would fail on it.

protected function checkRef(string $ref): void
$refstring
retournevoid

conclude()

SetupWizard.php:1514

What to do next, in order, with the commands to type.

protected function conclude(): void
retournevoid

credentialsText()

SetupWizard.php:1404
protected function credentialsText(): ?string
retournenull | stringthe credentials file once the answers are in it, null when there is none and none is needed.

declarationText()

SetupWizard.php:1389
protected function declarationText(): string
retournestringdeploy.json once the answers are in it: its own text, edited -- every key of every server and target written, and each one with a comment saying what it does (Declaration).

describeServer($row)

SetupWizard.php:535
protected function describeServer(array $row): string
$rowarray
retournestringhow a server is reached, how it lets you in, and whether its host key is pinned.

directive($text, $pattern, $value)

SetupWizard.php:1248
protected function directive(string $text, string $pattern, string $value): string
$textstring
$patternstring
$valuestring
retournestring$text with the value of the directive $pattern matches -- its first group kept -- replaced by $value.

entity($name, $row)

SetupWizard.php:1597
protected function entity(string $name, ?array $row = null): MMO\admin\entities\Target
$namestring
$row = nullnull | arrayits declaration (null: the one it has).
retourneTargetthe target as the store would load it: its own values, on its server.

fingerprint($value)

SetupWizard.php:780
protected function fingerprint(string $value): ?string
$valuestringa fingerprint as a tool prints it: MD5:aa:bb..., AABB..., with or without colons.
retournenull | stringlowercase hex pairs joined by colons -- what \MMO\core\server\SSH compares -- or null when it is not 32 (MD5) or 40 (SHA1) hex digits. A base64 fingerprint (SHA256:...) is not one the ssh2 extension can compute.

freeName($prefix, $taken)

SetupWizard.php:1737
protected function freeName(string $prefix, array $taken): string
$prefixstring
$takenarray
retournestringthe first of {prefix}1, {prefix}2... that is not taken.

hostKeyFile($type)

SetupWizard.php:767
protected function hostKeyFile(string $type): string
$typestring
retournestringwhere the server keeps the public key of that kind.

ignoresNeeded()

SetupWizard.php:1363

The .gitignore rules the files about to be written need and nothing gives them: a private file is never written where git would take it, whichever step made it.

protected function ignoresNeeded(): array
retournearray

introduce($full)

SetupWizard.php:221
protected function introduce(bool $full = true): void
$full = trueboolevery step follows: say what they are about. One step alone says only what it has to.
retournevoid

isExample($section, $name)

SetupWizard.php:1649
protected function isExample(string $section, string $name): bool
$sectionstring
$namestring
retourneboolwhether a server or a target is still the template's example, untouched.

isIgnored($file)

SetupWizard.php:375
protected function isIgnored(string $file): bool
$filestring
retourneboolwhether git would leave $file, relative to the project, out of a commit.

mask($text)

SetupWizard.php:1468
protected function mask(string $text): string
$textstring
retournestring$text with the value of every secret-shaped key replaced by ****.

missingRules($template, $have)

SetupWizard.php:417

The rules of the template a project's .gitattributes lacks. A rule the template anchors to the root (/src/ export-ignore) is there when the project has it bare (src/ export-ignore): bare, it matches at any depth, the root included -- broader than the template asks, which is the project's own choice.

protected function missingRules(string $template, string $have): array
$templatestring
$havestring
retournearraythe template's rules, as the template writes them

missingTemplates()

SetupWizard.php:327
protected function missingTemplates(): array
retournearrayfile relative to the project => template, for every template file the project lacks.

moveSecret($path, $key, $what)

SetupWizard.php:289
protected function moveSecret(array $path, string $key, string $what): void
$patharraywhere the secret is: a server's or a target's row.
$keystring
$whatstringhow to name the row.
retournevoid

need($answer)

SetupWizard.php:1544
protected function need(mixed $answer): mixed
$answermixedwhat a prompt returned.
retournemixed$answer, once it is known not to be null.
lèvenobody answered: the input ended, or an invalid answer came from something that is not a terminal.

objectify($data)

SetupWizard.php:1608
protected function objectify(array $data): array
$dataarray
retournearray$data with an empty object written {} where deploy.json has objects: [] is an empty list.

panelPath($path, $root)

SetupWizard.php:1097
protected function panelPath(string $path, ?string $root): string
$pathstring
$rootnull | string
retournestring$path as a webspace panel names it: relative to the server's root, when it is under it.

pickName($question, $names, $default)

SetupWizard.php:1571
protected function pickName(string $question, array $names, string|int|null $default = null): string
$questionstring
$namesarraykeys of the declaration -- PHP makes a name like 1 an int.
$default = nullstring | int | null
retournestringone of $names -- the only one, without asking.

privateFiles()

SetupWizard.php:362
protected function privateFiles(): array
retournearrayarray{0: string, 1: string}> file relative to the project => [the .gitignore rule ignoring it, why it must be]: what the project keeps that cannot be shared. Kept in the project, private, and out of git -- never in a folder of the user's.

readHostKey($host, $port)

SetupWizard.php:738

Read the host key a server presents, the way the deployment's own connection will check it.

protected function readHostKey(string $host, int $port): ?array
$hoststring
$portint
retournenull | arraystring, sha1: string, md5: string}|null null when it could not be read, and why is printed.

readWebspaceRoot($server, $row, $secrets)

SetupWizard.php:1068
protected function readWebspaceRoot(string $server, array $row, array $secrets): ?string
$serverstring
$rowarray
$secretsarray
retournenull | stringwhat pwd prints on it, null when that is not an absolute path.
lèvewhen it cannot be reached.

reference($path)

SetupWizard.php:1642
protected function reference(array $path): mixed
$patharray
retournemixeda reference to the value of $data at $path.

relativePaths($paths)

SetupWizard.php:1777
protected function relativePaths(array $paths): ?string
$pathsarray
retournenull | stringwhy these paths are not paths of a release, or null.

relativeTo($root, $path, $default)

SetupWizard.php:1089
protected function relativeTo(?string $root, ?string $path, string $default): string
$rootnull | stringthe server's root.
$pathnull | stringa folder as deploy.json writes it (null: none yet).
$defaultstringwhat to propose when there is none.
retournestring$path as it is best written: relative to the root when it is under it, its last folder under the root when it is outside it -- another account's path, a placeholder -- and as it is otherwise.

renameKey($values, $old, $new)

SetupWizard.php:1622
protected function renameKey(array $values, string $old, string $new): array
$valuesarray
$oldstring
$newstring
retournearray$values with the key $old named $new, where it was.

review($changes)

SetupWizard.php:1450

Show every change: what is added, removed, run -- secrets masked.

protected function review(array $changes): void
$changesarray
retournevoid

rules($text)

SetupWizard.php:424
protected function rules(string $text): array
$textstring
retournearraythe rules of a .gitattributes text, spaces normalized.

run($only)

SetupWizard.php:158

Ask, explain, show, write.

function run(?string $only = null): bool
$only = nullnull | stringone step of STEPS alone -- followed by the review, which is where writing happens.
retourneboolwhether anything was written.
lèvewhen $only names no step, or deploy.json is not JSON at all.

saveServer($old, $new, $row, $secrets)

SetupWizard.php:819
protected function saveServer(?string $old, string $new, array $row, array $secrets): void
$oldnull | stringits name so far (null for a new one).
$newstring
$rowarray
$secretsarray
retournevoid

setting($key)

SetupWizard.php:1666
protected function setting(string $key): array
$keystring
retournearraya list setting of ProductionController, as it is configured.

stepInstall()

SetupWizard.php:1162

installTemplates and postInstall: the vhost install sets up on a server of yours -- and on no other.

protected function stepInstall(): void
retournevoid

userSshConfig()

SetupWizard.php:1677
protected function userSshConfig(): ?MMO\admin\helpers\SshConfig
retournenull | SshConfigthe user's own ~/.ssh/config: only ever read, for an alias to copy into the project.

validate($changes)

SetupWizard.php:1431

Refuse what mmo.admin would refuse: a deploy.json that does not load, a PHP file that does not parse.

protected function validate(array $changes): ?string
$changesarraychanges
retournenull | stringwhy, or null when everything is fine.

valueAt($path)

SetupWizard.php:1629
protected function valueAt(array $path): mixed
$patharray
retournemixedthe value of $data at $path, null when there is none.

webspaceRoot($server, $row, $secrets)

SetupWizard.php:1048

The folder a webspace account lands in: what pwd prints there.

protected function webspaceRoot(string $server, array $row, array $secrets): ?stringRead over the same ssh connection a deployment opens, with the answers given so far -- the alias about to be written, the password about to be stored. Read once per server; nothing else is run.
$serverstring
$rowarraythe server's declaration, as answered so far.
$secretsarraywhat the credentials file will hold for it.
retournenull | stringnull when it could not be read, and why is printed: the root is then asked plainly.

withoutComments($value)

SetupWizard.php:1785
protected function withoutComments(mixed $value): mixed
$valuemixed
retournemixed$value without the keys starting with //, at any depth: comments, as Store reads them.

write($filename, $text, $mode)

SetupWizard.php:1496

Write a file beside, then move it over: a file half written is never the one read.

protected function write(string $filename, string $text, ?int $mode): void
$filenamestring
$textstring
$modenull | intapplied BEFORE anything is written in it: a secret never sits in a file others can read. null: the mode it has, or the default for a new file.
retournevoid

__construct($filename, $credentialsFilename, $templateFolder, $git, $sshConfig, $settings, $dryRun)

SetupWizard.php:131
function __construct( string $filename, ?string $credentialsFilename = null, ?string $templateFolder = null, ?MMO\git\helpers\Repository $git = null, ?MMO\admin\helpers\SshConfig $sshConfig = null, array $settings = [], bool $dryRun = false )
$filenamestringthe project's deploy.json, which may not exist yet.
$credentialsFilename = nullnull | stringnull: deploy.credentials.json beside it.
$templateFolder = nullnull | stringmmo.admin's templates (null: this library's).
$git = nullnull | Repositorythe project's repository (null: the folder of deploy.json, if it is one).
$sshConfig = nullnull | SshConfignull: the project's deploy.ssh.config, beside deploy.json.
$settings = []arraywhat ProductionController is configured with: protectedTags, buildCommands, include, installTemplates, postInstall, repository (whether one is set), bootstrap (the file configuring it).
$dryRun = falseboolask everything, show every change, write nothing.