Index

Schema

MMO\core\schemas · 1 symbol · generated 30 Sep 2026

class

Schema

Schema.php:100

Implementation of JSON Schema

class MMO\core\schemas\Schema extends MMO\core\helpers\Container implements MMO\core\interfaces\iMutationObserver, MMO\core\interfaces\iSchema
Namespace
MMO\core\schemas
Extends
Container
Implements
iMutationObserver, iSchema
## Types The type keyword can be either a string or an array e.g. `{ "type": "number" }` `{ "type": ["number", "string"] }` Supported types: - string - integer - number: php float - boolean - null - instance: php object - object: php array - array: php array with only numerical index (list) ## Information - $id: {string} a unique url for this schema - $class: {?string} the php classname represented by this schema - $alias: {get: ?string, set: ?string} the real path to get/set data - label: {string} short descriptive title - title: {string} descriptive title - description: {string} longer explanation about purpose of data described by the schema - default: {*} a default value - order: {integer} value to order properties - icon: {string} an icon name or an utf8 value - readOnly: {boolean} - store: {boolean} (default true if it has a setter and a getter) - noindex: {true} (remove from index) - examples: {array[*]} list of examples that validate against the schema - $comment: {string} for adding a comment to the schema (not used for validation) - $links: {array[string: string]} a map of links to access data described by this schema - api: the link to interact with the data api - index: the link to get a list of the resources available in the api ## Constraints ### string - minLength: {integer} - maxLength: {integer} - pattern: {string} regular expression in ECMA 262 syntax - format: {string} one of the names [`validateFormat`](https://mmoframework.fr/documentation/mmo.core/php/schemas.md#validateformat) checks: date, time, datetime, date-utc, datetime-u, color, style, phone, uri, uriref, uri-reference, email, ip-address, ipv4, ipv6, host-name, hostname. Any other name passes: JSON Schema's own `date-time` and `regex` are NOT checked -- the framework spells the first one `datetime`. ### integer / number - multipleOf: {number} - minimum: {number} >= - exclusiveMinimum: {number} > - maximum: {number} <= - exclusiveMaximum: {number} < ### object - minProperties: {integer} - maxProperties: {integer} - required: {array[string]} list of property names - dependentRequired: {array[string: array[string]]} list of required properties for object with a property matching the key - dependentSchemas: {array[string: schema]} schema to apply on objects with a property matching the key - properties: {array[string: schema]} map of property names to schemas - patternProperties: {array[string: schema]} if the property's name match the regex (the key), apply the schema - additionalProperties: {schema} schema to apply to other properties not described in `properties` - propertyNames: {schema} schema to apply on the property's name - unevaluatedProperties: {schema} schema to apply to properties not evaluated, even with combined schemas (anyOf, allOf, ...) ### array - minItems: {integer} - maxItems: {integer} - uniqueItems: {boolean} tells if all items must be unique - items: {schema} schema to apply on the list items - prefixItems: {array[integer: schema]} schema to apply to the items at the given key - contains: {schema} schema to apply to a minimum of minContain (or 1) and a maximum of maxContain (or 1) of items - minContains: {integer} - maxContains: {integer} - unevaluatedItems: {schema} schema to apply to items not evaluated, even with combined schemas (anyOf, allOf, ...) ### instance - instanceOf: {array[string]} the instance must be an instance of at least one these classnames ### other - enum: {array[*]} data must deeply equal one item in the array - const: {*} data must deeply equal this value - allOf: {array[schema]} data must validate all these schemas - anyOf: {array[schema]} data must validate one of these schemas - oneOf: {array[schema]} data must validate only one of these schemas - not: {schema} data must not validate this schema - if: {schema} if data validate this schema, it must validate the `then` schema, else the `else` schema - then: {schema} - else: {schema}

Index

SCHEMAS_PROPERTY
SCHEMA_PROPERTY
anchors
addRequired($key)Add $key to the 'required' list (a no-op if it's already there).
coerce($value, $opts)Coerce $value to match this schema's declared type(s), trying each in turn (Coercer::Coerce) -- 'enum'/'const' take priority (coerced to match one of the allowed values), 'instanceOf' adds the…
coerceItem($key, $value, $opts)
coerceProperty($key, $value, $opts)
createValidator($value)Build the right Validator subclass for $value, based on this schema's declared 'type' (or, if none, $value's own PHP type -- see typeOf).
Defs($classes) staticCreate a list of definition schema from a list of classes.
Fetch($url) staticSame as Container::Fetch, ensuring the built-in global types (InitGlobalTypes) are registered first.
From($schema, $parent) staticBuild a schema from a flexible, convenient input.
FromClass($class, $parent) static
FromEnum($class, $parent) staticCreate a schema from an enum
get($id, $default)Same as Container::get, also checking the root schema's $anchor-registered sub-schemas (setContent) first.
getAnchor()
getDefault()Get schema default value.
getDescription()
getIcon()
getInstanceTypes($recursive)Collect every class/interface name this schema (and, per $recursive, its sub-schemas) could produce via 'instanceOf' -- used e.g.
getItemSchema($index)
getLabel($content)
getLabelProperties()
getName()
getOrder()
getPHPClass()
getPropertySchema($key)
getSchema($path, $_cyclic)Get the schema at the given path
getSchemaFor($instancePath)Get the schema for an object path (using 'properties' or 'items' sub schemas)
getTitle($content)Same as getLabel, for the 'title' keyword (falling back to getLabel if there's no 'title').
getTitleProperties()
getUniquePropertyGroups()
getVisibleProperties()Get all the readable properties
GlobalTypes() static
has($id)NOTE: this used to check $this->anchors -- but anchors are only ever registered on the ROOT schema's
hasDefault()Tells if schema has a default value
hasNoIndex()
InitGlobalTypes() staticRegister the bare {"type": "..."} schema for each of TYPES globally, once.
isDateTime()Test if schema represents a datetime
isInstanceOf($class, $direct)Test if schema is an instance of a class
isList()
isNullable()NOTE: this used to omit the ??[] fallback that every other 'type'-array check in this class uses (e.g.
isObject()
isPropertyNullable($key)
isString()
mutate($type, $path, $value, $oldValue)
printItem($value, $options)Render one value for a {placeholder} in getLabel/getTitle's templates: an iEntity's title, a backed enum's value, a date as 'd/m/Y', or its plain string cast otherwise.
RegisterGlobalType($id, $schema) staticRegister a custom named schema globally, reachable afterward via its TypeId (e.g.
resolve($url, $_cyclic)Resolve a JSON Schema $ref (or any URI) to the schema it points to.
resolveInstanceOf($allowEnum)Get the schema associated to the first instanceOf
setContent($content)Load raw schema data: sets $id/registers an $anchor/$dynamicAnchor on the root, converts a $dynamicRef to a plain $ref (dynamic refs aren't otherwise supported), triggers mutate for …
setId($id)
setType($type)Set the type
sort($array, $byKeys)Order the keys of an array using the properties order
toRegex($withDelimiter)Build a regular expression matching (roughly) the same values this schema would accept -- useful e.g.
TypeId($class) static
validate($value, $errors)Validate a value through this schema
walkSchemaFor($instancePath)Walk through all the schema in a path, resolving the instanceOf on the way.

Constants2

SCHEMAS_PROPERTY

const SCHEMAS_PROPERTY = […8 items]

SCHEMA_PROPERTY

const SCHEMA_PROPERTY = […10 items]

Properties1

anchors

#[MMO\core\attributes\Serialize(false)] protected array $anchors = []
Type
array

Methods54

addRequired($key)

Schema.php:690

Add $key to the 'required' list (a no-op if it's already there).

function addRequired(string $key): void
$keystring
returnsvoid

coerce($value, $opts)

Schema.php:872

Coerce $value to match this schema's declared type(s), trying each in turn (Coercer::Coerce) -- 'enum'/'const' take priority (coerced to match one of the allowed values), 'instanceOf' adds the 'instance' type, and an untyped-but-structured schema ('properties' implies 'object', 'items'/'prefixItems' implies 'array') is coerced accordingly; a schema with no type information at all is left untouched.

function coerce(mixed $value, array $opts = []): mixed
$valuemixed
$opts = []array
returnsmixed
throwsif $value can't be coerced to any of the schema's types.

coerceItem($key, $value, $opts)

Schema.php:919
function coerceItem(?int $key, mixed $value, array $opts = []): mixed
$keynull | int
$valuemixed
$opts = []array
returnsmixed$value coerced per item $key's own schema (getItemSchema), or returned unchanged if there's none.

coerceProperty($key, $value, $opts)

Schema.php:909
function coerceProperty(string $key, mixed $value, array $opts = []): mixed
$keystring
$valuemixed
$opts = []array
returnsmixed$value coerced per property $key's own schema (getPropertySchema), or returned unchanged if $key has none.

createValidator($value)

Schema.php:929

Build the right Validator subclass for $value, based on this schema's declared 'type' (or, if none, $value's own PHP type -- see typeOf).

function createValidator(mixed $value): MMO\core\schemas\Validator
$valuemixed
returnsValidator

Defs($classes)

staticSchema.php:122

Create a list of definition schema from a list of classes.

static function Defs(self|string ...$classes): arrayThese classes MUST implements iSchemaProvider or be an enum.
...$classesself | string
returnsarray
throws

From($schema, $parent)

staticSchema.php:163

Build a schema from a flexible, convenient input.

static function From( MMO\core\interfaces\iSchema|array|string|bool $schema, ?self $parent = null ): MMO\core\interfaces\iSchema
$schemaiSchema | array | string | boolan existing iSchema (returned as-is); a bool (TrueSchema/FalseSchema); a type name string (shorthand for ['type' => $schema]); or a raw schema array (a lone $ref key resolves against $parent immediately instead of building a new schema).
$parent = nullnull | self
returnsiSchema

FromClass($class, $parent)

staticSchema.php:201
static function FromClass(string $class, ?MMO\core\interfaces\iSchema $parent = null): MMO\core\interfaces\iSchema
$classstring
$parent = nullnull | iSchema
returnsiSchema

FromEnum($class, $parent)

staticSchema.php:185

Create a schema from an enum

static function FromEnum(string $class, ?self $parent = null): self
$classstring
$parent = nullnull | self
returnsself
throws

getDefault()

Schema.php:579

Get schema default value.

function getDefault(): mixedWARNING: return NULL when schema has no default OR if default is null. Use [`hasDefault()`](https://mmoframework.fr/documentation/mmo.core/php/schemas/Schema.md#schema-hasdefault) to test if schema has a set default value.
returnsmixed

getDescription()

Schema.php:559
function getDescription(): string
returnsstringthe 'description' keyword, or ''.

getInstanceTypes($recursive)

Schema.php:774

Collect every class/interface name this schema (and, per $recursive, its sub-schemas) could produce via 'instanceOf' -- used e.g. by Defs to discover which classes' own schemas need registering.

function getInstanceTypes(bool $recursive = false): array
$recursive = falseboolif true, also descend into 'items'/'prefixItems'/'properties'/'additionalProperties' (always descends into 'anyOf'/'oneOf'/'allOf' regardless).
returnsarrayde-duplicated class/interface names.

getItemSchema($index)

Schema.php:723
function getItemSchema(?int $index = null): ?MMO\core\interfaces\iSchema
$index = nullnull | intif given and covered by @see 'prefixItems', that positional schema; otherwise @see 'items' (if any), else null.
returnsnull | iSchema

getLabel($content)

Schema.php:533
function getLabel(ArrayAccess|array|null $content = null): string
$content = nullArrayAccess | array | nullif given and the schema has a 'label' template, render it against this data (renderTemplate, using printItem for each placeholder).
returnsstringthe rendered label, or the raw 'label' template/'' if $content isn't given.

getLabelProperties()

Schema.php:541
function getLabelProperties(): array
returnsarrayproperty names referenced by the 'label' template's {placeholder}s.

getName()

Schema.php:524
function getName(): ?string
returnsnull | stringthe bare name this schema was globally registered under (TypeId), or null if it isn't a global type.

getOrder()

Schema.php:564
function getOrder(): ?int
returnsnull | intthe 'order' keyword (used by sort to order sibling properties/items).

getPropertySchema($key)

Schema.php:712
function getPropertySchema(string $key): ?MMO\core\interfaces\iSchema
$keystring
returnsnull | iSchema$key's own schema (@see 'properties'), else the first matching @see 'patternProperties' pattern's schema, else @see 'additionalProperties' (if any), else null.

getSchema($path, $_cyclic)

Schema.php:290

Get the schema at the given path

function getSchema(array|string $path, int $_cyclic = 10): MMO\core\interfaces\iSchema
$patharray | stringthe json path of the schema
$_cyclic = 10intinternal
returnsiSchema

getSchemaFor($instancePath)

Schema.php:352

Get the schema for an object path (using 'properties' or 'items' sub schemas)

function getSchemaFor(array|string $instancePath): ?MMO\core\interfaces\iSchema
$instancePatharray | string
returnsnull | iSchemanull if not known: a path through a property typed with an interface (walkSchemaFor)

getTitleProperties()

Schema.php:554
function getTitleProperties(): array
returnsarrayproperty names referenced by the 'title' template's {placeholder}s.

getUniquePropertyGroups()

Schema.php:685
function getUniquePropertyGroups(): array
returnsarraythe 'uniquePropertyGroups' keyword (this framework's own extension: groups of properties whose combined values must be unique).

getVisibleProperties()

Schema.php:699

Get all the readable properties

function getVisibleProperties(): array
returnsarray

has($id)

Schema.php:364

NOTE: this used to check $this->anchors -- but anchors are only ever registered on the ROOT schema's

function has($id): bool
See
$anchors (setContent), same as get() correctly checks via $this->getRoot()->anchors. So has() only ever worked when called directly on the root; called on any nested sub-schema, it always missed an anchor that get() itself could find on that very same schema. Fixed to match get()'s own logic.
$id
returnsbool

hasDefault()

Schema.php:600

Tells if schema has a default value

function hasDefault(): bool
returnsbool

hasNoIndex()

Schema.php:633
function hasNoIndex(): bool
returnsboolthe 'noindex' keyword (marks this schema/property as excluded from search indexing).

InitGlobalTypes()

staticSchema.php:253

Register the bare {"type": "..."} schema for each of TYPES globally, once. Called automatically wherever a global schema might be looked up (GlobalTypes/Fetch).

static function InitGlobalTypes(): void
returnsvoid

isDateTime()

Schema.php:659

Test if schema represents a datetime

function isDateTime(): bool
returnsbool

isInstanceOf($class, $direct)

Schema.php:643

Test if schema is an instance of a class

function isInstanceOf(?string $class = null, bool $direct = false): bool
$class = nullnull | stringif null only check if the schema represents an instance
$direct = falseboolif false, $class can be an extension of the instance present in this schema
returnsbool

isList()

Schema.php:618
function isList(): bool
returnsboolwhether this schema describes a list (an explicit 'items' keyword, or 'array' in its 'type').

isNullable()

Schema.php:671

NOTE: this used to omit the ??[] fallback that every other 'type'-array check in this class uses (e.g.

function isNullable(): bool
See
isList/isObject/isString), so a schema with no 'type' keyword at all (a completely valid, common case -- e.g. a bare {"enum": [...]}) crashed with a TypeError instead of correctly answering "not nullable". Fixed to match the established pattern.
returnsboolwhether this schema's 'type' includes 'null'.

isObject()

Schema.php:623
function isObject(): bool
returnsboolwhether this schema describes a map (an explicit 'properties' keyword, or 'object' in its 'type').

isString()

Schema.php:628
function isString(): bool
returnsboolwhether this schema's 'type' includes 'string'.

mutate($type, $path, $value, $oldValue)

Schema.php:440
function mutate(string $type, array $path, mixed $value, mixed $oldValue): bool
See
iMutationObserver hook, invoked whenever a schema property is set/changed (including once for every top-level keyword right after setContent loads new content). Keeps this schema's internal invariants: schema-shaped properties (SCHEMA_PROPERTY/SCHEMAS_PROPERTY) are normalized into real Schema/, TrueSchema/FalseSchema instances (via From) as soon as they're set; 'type' is re-normalized (setType); a scalar 'instanceOf' is wrapped into a single-element array; and, on deletion, a removed sub-schema's anchor (if any) is unregistered from the root.
$typestring'=' (set) or '-' (delete).
$patharray
$valuemixed
$oldValuemixed
returnsboolalways true (the mutation is always allowed).

printItem($value, $options)

Schema.php:511

Render one value for a {placeholder} in getLabel/getTitle's templates: an iEntity's title, a backed enum's value, a date as 'd/m/Y', or its plain string cast otherwise.

function printItem(mixed $value, array $options): string
$valuemixed
$optionsarray
returnsstring

RegisterGlobalType($id, $schema)

staticSchema.php:247

Register a custom named schema globally, reachable afterward via its TypeId (e.g. by $ref).

static function RegisterGlobalType(string $id, array $schema): MMO\core\schemas\Schema
$idstring
$schemaarray
returnsSchema

resolve($url, $_cyclic)

Schema.php:479

Resolve a JSON Schema $ref (or any URI) to the schema it points to.

function resolve(string $url, int $_cyclic = 10): MMO\core\interfaces\iSchema
$urlstringa bare fragment ('#', '#/path', '#anchorName'), a bare (possibly relative) URL, or a URL with a fragment -- resolved against this schema's root's own $id when relative.
$_cyclic = 10intinternal recursion guard.
returnsiSchema
throwsif references form a cycle too deep to resolve ($_cyclic).
throwsif $url points at something that isn't a valid schema.

resolveInstanceOf($allowEnum)

Schema.php:315

Get the schema associated to the first instanceOf

function resolveInstanceOf(bool $allowEnum = true): ?MMO\core\interfaces\iSchema
$allowEnum = truebool
returnsnull | iSchema
throws

setContent($content)

Schema.php:379

Load raw schema data: sets $id/registers an $anchor/$dynamicAnchor on the root, converts a $dynamicRef to a plain $ref (dynamic refs aren't otherwise supported), triggers mutate for every top-level keyword (so schema-shaped properties -- SCHEMA_PROPERTY/SCHEMAS_PROPERTY -- are converted into actual Schema/TrueSchema/FalseSchema instances), then, if a root-level $ref is present, resolves and merges it in (a $ref alongside other keywords -- unlike From's lone-$ref shortcut -- augments this schema rather than replacing it).

function setContent(array $content): void
$contentarray
returnsvoid

setId($id)

Schema.php:416
function setId(?string $id): void
$idnull | stringresolved against the root schema's own id if it's relative (per RFC 3986), so every schema's $id ends up absolute.
returnsvoid

setType($type)

Schema.php:751

Set the type

function setType(array|string|null $type): void
$typearray | string | nullif string and not a standard type, parseType is used
returnsvoid

sort($array, $byKeys)

Schema.php:733

Order the keys of an array using the properties order

function sort(array &$array, bool $byKeys = true): void
$arrayarray
$byKeys = truebool
returnsvoid

toRegex($withDelimiter)

Schema.php:816

Build a regular expression matching (roughly) the same values this schema would accept -- useful e.g. for a route parameter pattern.

function toRegex(bool $withDelimiter = true): stringNOTE: the 'null'/'boolean'/'integer'/'number' type checks here used to read `$this->content['type']` directly (no `??[]` fallback, unlike [`isList`](https://mmoframework.fr/documentation/mmo.core/php/schemas/Schema.md#schema-islist)/[`isObject`](https://mmoframework.fr/documentation/mmo.core/php/schemas/Schema.md#schema-isobject)/[`isString`](https://mmoframework.fr/documentation/mmo.core/php/schemas/Schema.md#schema-isstring) elsewhere in this class), so calling this on a schema with no 'type' keyword at all (a valid, common case -- e.g. a bare enum/const schema) crashed with a TypeError instead of just skipping those type-specific regex fragments. Fixed.
$withDelimiter = truebool
returnsstring

validate($value, $errors)

Schema.php:955

Validate a value through this schema

function validate(mixed $value, ?array &$errors = null): bool
$valuemixed
$errors = nullnull | arrayif passed, this reference will hold all the errors encountered, keyed by the failing value's key: each has its keywordLocation (the schema's path where the validator failed) and its message; its JSON form (jsonSerialize) adds instanceLocation and names the message error
returnsbooltrue if valid. if false $errors will contain the errors.

walkSchemaFor($instancePath)

Schema.php:330

Walk through all the schema in a path, resolving the instanceOf on the way.

function walkSchemaFor(array|string $instancePath): GeneratorA bool schema has no sub-schema: past one, the walk yields null and stops. That is where a property typed with an interface leads (an [`iSchemaProvider`](https://mmoframework.fr/documentation/mmo.core/php/interfaces/iSchemaProvider.md#ischemaprovider) interface resolves to `true`: [`FromClass`](https://mmoframework.fr/documentation/mmo.core/php/schemas/Schema.md#schema-fromclass)), whatever class its value is.
$instancePatharray | stringthe path to walk to
returnsGeneratorstring $key => ?iSchema, null from the first key whose schema is not known
throws
iterator_to_array(File::Schema()->walkSchemaFor('owner/username')); // ['owner' => Schema, 'username' => null]: an owner is an iClient
Inherited members (30)
ConstantsDeclared byDescription
MAX_REFERENCE_DEPTHContainer
PropertiesDeclared byDescription
contentContainer
idContainer
IDSContainer
parentContainer
MethodsDeclared byDescription
clear()ContainerEmpty the underlying content, keeping the object itself.
count()Container\Countable::count
delete($id)ContainerRemove the value at $id and return it.
Exists($url)Container
getContent()Container
getId()Container
getIterator()Container\IteratorAggregate::getIterator
getParent()Container
getRoot()Container
inject($id, $config, $recursive)ContainerMerge $config into the content at $id (each of $config's own keys is injected at $id/$key).
isEmpty()Container
jsonSerialize($options)Container
keys()Container
load($configs)ContainerMerge one or more configs into this container's content (via inject).
loadArray($data)ContainerLoad every entry of a plain array into the content, through offsetSet (so any offsetSet() override defined by the class using this trait, e.g.
offsetExists($key)Container\ArrayAccess::offsetExists
offsetGet($key)Container\ArrayAccess::offsetGet
offsetSet($key, $value)Container\ArrayAccess::offsetSet -- a null $key appends ($bag[] = $value), like a plain PHP array.
offsetUnset($key)Container\ArrayAccess::offsetUnset -- on a list (sequential integer keys, as produced by $bag[] = ...), the element is spliced out (closing the gap and reindexing), matching \unset() semantics on a plain …
push($id, $value, $create)ContainerPush a value in content
set($id, $value, $create)ContainerSet a value at $id, creating intermediate structure as needed.
toArray()ContainerConvert the content to a plain array, recursively converting any nested iArray value (e.g.
UnFetch($url)ContainerForget the container registered under $url (it can be Fetch-ed again afterward, rebuilding it).
UnFetchAll()ContainerForget every registered container.
__construct($content, $id, $parent)ContainerCreate container