Index

Store

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

class

Store

Store.php:35

Everything the deployment tooling knows, as entities: which projects exist, which machines they run on, which targets live on those machines, and what has actually been deployed to each.

class MMO\admin\helpers\Store
Namespace
MMO\admin\helpers
See
Target collections. The store NEVER writes this file, and no deployment does. A deployment topology is reviewed source, not application state, and a tool that can rewrite it is a tool that can quietly change where a release goes. SetupWizard edits it -- only once a person has answered and read the diff. 2. The history -- a JsonRepository at .mmo/deploy.history.json in the project (HISTORY), filled by sync -- and after every deployment -- from each target's own journal. This one is ordinary, writable state, and it is what the dashboard reads for a fleet-wide view without connecting to 27 machines to draw a page. It is this machine's record, not the project's: git-ignored, and readable by you alone., Credentials, and every ssh alias through SshConfig, from files beside the declaration git ignores. deploy.json is checked for secret-shaped keys on load (assertNoSecrets) and refuses to parse if it has any, so the previous pipeline's failure -- a production password committed to 31 branches -- cannot be repeated by someone taking the obvious shortcut.
Two stores in one, deliberately: 1. **The declaration** -- `deploy.json`, committed and code-reviewed, read into [`Project`](https://mcp.mmoframework.fr/documentation/mmo.admin/php/entities/Project.md#project) / [`Server`](https://mcp.mmoframework.fr/documentation/mmo.admin/php/entities/Server.md#server) / Nothing it reads or writes is outside the project folder. Everything secret is resolved through
$store = Store::FromFile('{root}/deploy.json'); $store->getTargets()->getById('demo'); $store->getDeployments()->query(['target' => 'demo'], sort: ['-date']);

Index

HISTORYwhere a project keeps this machine's deployment history, relative to the folder of deploy.json.
SECRETSkeys that must never appear in the committed declaration, whatever level they appear at.
credentials
filename
history
historyFilename
projectName
projects
servers
sshConfig
targets
assertLoaded($entity, $what)Refuse an entity whose data did not survive being loaded.
assertNoSecrets($data, $path)Refuse a declaration carrying anything secret-shaped, at any depth.
assertRow($row, $class, $what)Refuse a record carrying a key the entity does not declare.
debugName()
FromFile($filename, $credentialsFilename, $history, $sshConfigFilename) static
getCredentials()
getDeployments()
getFilename()
getHistory($target, $count)
getHistoryFilename()
getHistoryRepository()
getProject($name)
getProjectName()
getProjects()
getServer($name)
getServers()
getSshConfig()
getTargets()
hasHistory()
loadProjects($data)
loadServers($data)
loadTargets($data)Every target as it is written: nothing is inherited, so reading a target is reading what it is.
mirror($entries)Merge a target's own journal into the local history, skipping what is already there.
saveHistory()Write what mirror added.
StateFilename($root) staticWhere a project's synced history lives on this machine: HISTORY, in the project.
stripComments($data)Drop every //-prefixed key, at any depth.
suggest($key, $known)
__construct($data, $filename, $credentials, $stateFilename, $sshConfig)

Constants2

HISTORY

where a project keeps this machine's deployment history, relative to the folder of deploy.json.

const HISTORY = '.mmo/deploy.history.json'

SECRETS

keys that must never appear in the committed declaration, whatever level they appear at.

const SECRETS = […9 items]

Properties9

credentials

protected ?MMO\admin\helpers\Credentials $credentials = null
Type
null | Credentials

filename

protected ?string $filename = null
Type
null | string

history

protected ?MMO\core\entities\JsonRepository $history = null
Type
null | JsonRepository

historyFilename

protected ?string $historyFilename = null
Type
null | string

projectName

protected ?string $projectName = null
Type
null | string

projects

protected MMO\core\entities\Collection $projects
Type
Collection

servers

protected MMO\core\entities\Collection $servers
Type
Collection

sshConfig

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

targets

protected MMO\core\entities\Collection $targets
Type
Collection

Methods28

assertLoaded($entity, $what)

Store.php:305

Refuse an entity whose data did not survive being loaded.

protected function assertLoaded(object $entity, string $what): voidAn entity records a value it could not coerce in [`aEntity::getErrors`](https://mcp.mmoframework.fr/documentation/mmo.core/php/classes/aEntity.md#aentity-geterrors) and carries on with the property at its default -- which, for a deployment declaration, is silence where there should be a stop. A `vars` map that failed to coerce leaves `{placeholders}` unresolved in a path; a `shared` list that failed leaves live data inside a release, to be deleted by the next prune. Neither is something to find out about on a server.
$entityobject
$whatstring
returnsvoid
throws

assertNoSecrets($data, $path)

Store.php:439

Refuse a declaration carrying anything secret-shaped, at any depth.

protected function assertNoSecrets(array $data, string $path = ''): voidThis is the structural half of keeping credentials out of git: `.gitignore` and code review are both things a hurried person skips, and the previous pipeline shows what that costs. A tool that will not START with a password in its configuration cannot be talked into committing one.
$dataarray
$path = ''string
returnsvoid
throws

assertRow($row, $class, $what)

Store.php:396

Refuse a record carrying a key the entity does not declare.

protected function assertRow(mixed $row, string $class, string $what): arraySilently ignoring unknown keys is what made the previous configuration dangerous rather than merely untidy: `"datbase"` produced a target with NO database, so `migrate` and `backup` quietly did nothing on it -- the tool reported success and the patches were simply never applied.
$rowmixed
$classstringthe entity class the record describes.
$whatstringhow to name it in an error.
returnsarray$row, unchanged.
throws

FromFile($filename, $credentialsFilename, $history, $sshConfigFilename)

staticStore.php:99
static function FromFile( string $filename, ?string $credentialsFilename = null, bool $history = true, ?string $sshConfigFilename = null ): static
$filenamestringthe declaration, resolved through filename.
$credentialsFilename = nullnull | stringnull: deploy.credentials.json beside the declaration (Credentials::DefaultFilename).
$history = trueboolload/persist the synced deployment history as well.
$sshConfigFilename = nullnull | stringnull: deploy.ssh.config beside the declaration (SshConfig::DefaultFilename).
returnsstatic
throwsif the declaration does not exist.

getDeployments()

Store.php:139
function getDeployments(): MMO\core\entities\Collection
returnsCollectionthe synced deployment history. @throws eNotFound when the store carries none.

getHistory($target, $count)

Store.php:244
function getHistory(?string $target = null, int $count = 20): array
$target = nullnull | stringonly this target's entries.
$count = 20int
returnsarraythe most recent mirrored deployments, newest first.

getProject($name)

Store.php:180
function getProject(?string $name = null): ?MMO\admin\entities\Project
$name = nullnull | string
returnsnull | Projectthe named project, or the single implicit one.

loadTargets($data)

Store.php:327

Every target as it is written: nothing is inherited, so reading a target is reading what it is.

protected function loadTargets(array $data): void
$dataarray
returnsvoid
throws

mirror($entries)

Store.php:219

Merge a target's own journal into the local history, skipping what is already there.

function mirror(iterable $entries): intThe target's journal is the truth -- it is written on the machine the deployment happened to, by the run that happened -- so this only ever adds. It never edits, never deletes, and never writes back to the target: a mirror that can change its source is not a mirror.
$entriesiterableDeployment, from Journal::all.
returnsinthow many entries were new.

saveHistory()

Store.php:156

Write what mirror added.

function saveHistory(): voidThe file is created private -- its folder 0700, itself 0600 -- before anything is written in it: who deployed what, when and from where is this machine's business, and it is not shared through git either.
returnsvoid

StateFilename($root)

staticStore.php:124

Where a project's synced history lives on this machine: HISTORY, in the project.

static function StateFilename(string $root): string
$rootstringthe project's folder -- the one holding deploy.json.
returnsstring

stripComments($data)

Store.php:374

Drop every //-prefixed key, at any depth.

protected function stripComments(array $data): arrayJSON has no comments, and a file that decides which machine a release lands on is exactly the kind of file that needs them. The convention costs nothing (`"//shared": "why these paths"` beside `"shared"`) and it means the strict key check below can stay strict: a key that is not a comment and not a declared property is a typo, and typos in this file are how a target quietly stops being backed up.
$dataarray
returnsarray

suggest($key, $known)

Store.php:416
protected function suggest(string $key, array $known): string
$keystring
$knownarray
returnsstring' Did you mean [x]?' when a close-enough key exists, '' otherwise.

__construct($data, $filename, $credentials, $stateFilename, $sshConfig)

Store.php:66
function __construct( array $data = [], ?string $filename = null, ?MMO\admin\helpers\Credentials $credentials = null, ?string $stateFilename = null, ?MMO\admin\helpers\SshConfig $sshConfig = null )
$data = []arraythe decoded declaration ({project, projects, servers, targets}).
$filename = nullnull | stringfor error messages only.
$credentials = nullnull | Credentialsresolved secrets, injected into every server.
$stateFilename = nullnull | stringwhere the synced history lives (null: no history).
$sshConfig = nullnull | SshConfigthe project's ssh aliases, injected into every server.