Download the PHP package meraki/schema without Composer
On this page you can find all versions of the php package meraki/schema. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download meraki/schema
More information about meraki/schema
Files in meraki/schema
Package schema
Short Description A library that provides a flexible, UI-agnostic solution for defining, validating, and serializing form schemas that can be used across multiple rendering environments and formats.
License MIT
Homepage https://github.com/merakiframework/schema
Informations about the package schema
meraki/schema
2.0is in alpha
mainis tagged2.0.0-alpha.3. It is a breaking rewrite of1.x: fields are immutable, input is objects rather than arrays, and every field parses to a value object. UPGRADING.md is the migration guide.The sibling packages are not migrated yet —
meraki/schema-htmlandmeraki/schema-jsondo not work against this tag. If you depend on either, stay on1.14.0, which is the last stable1.xrelease.The public API is otherwise settled; the scope string format is the one part deliberately left unfrozen (CHANGELOG.md and docs/ROADMAP.md.
Define a form once — its fields, their constraints, and the rules that wire them together — and validate input against that description. The core knows nothing about HTTP, HTML or JSON.
| Package | Responsibility |
|---|---|
meraki/schema |
Define and validate schemas (this package) |
meraki/schema-json |
Serialize a schema and read it back |
meraki/schema-html |
Render a form, normalize request input, produce messages |
Why this library
| Instead of | You get |
|---|---|
| Re-declaring the same rules in PHP and again in JavaScript | One definition that serializes |
| A regex that approximates a postcode | Per-country rules from libaddressinput, phone numbers from libphonenumber |
'age' => 'required\|integer\|min:18' |
Typed field objects your IDE and analyser can see |
| A validator welded to one framework | A core that knows nothing about HTTP, HTML or JSON |
| Registering a custom type with a factory | A class. Nothing to register — see EXTENDING.md |
The honest counterweight. It is far less proven than any mature alternative, and its messages arrive differently from theirs — as a pack you install rather than strings bundled with the validator, which is a real trade and not only an upside. docs/COMPARISON.md works through the alternatives in detail, including where each is the better choice.
Requirements
PHP 8.5+.
Installation
A first schema
Two things to know straight away, because both are unusual and both are deliberate.
A field is immutable. Every configuration method hands back a copy, so the result has to be kept:
That is what makes a schema safe to build once and share across concurrent requests. Build,
configure, then add().
Input is objects, not arrays. A value with named parts is an object; a value with many of something is an array:
PHP cannot tell an associative array from a list, so the distinction lives in the shape of the
input. Converting $_POST is the port's job. json_decode($body) already gives you objects — it
is the true second argument that does not.
Reading a result
Each field's result carries the same things, whatever kind of field it is:
Shape and constraints are different questions, and the order matters. If a value cannot be read at all, the constraints are skipped rather than failed — so a report names one problem once instead of once per constraint:
missing and unreadable are kept apart, because "this is required" and "this is not an email
address" are different sentences.
Where error messages come from
A verdict says what failed and what the limit was, with no wording attached:
That is enough to write your own sentence, and plenty of applications should. For the rest, wording is an installable language pack — data, not code:
dev-main while 2.0 is in alpha: the pack tracks a vocabulary that is still moving, so there is
nothing stable to pin to yet.
The pack is .mfr files in ICU MessageFormat 2
and nothing else — no PHP — so a Rust or JavaScript implementation of this library renders the same
sentences. Which is the point: the wording travels with the schema, not with the language you
happen to be writing in.
Three things hold whether or not you use it:
- The provider and the language both arrive with the request. One schema serves every reader.
- A missing language cannot change a verdict. Ask for one nobody has and you get the same failures with nothing to say about them.
- It is entirely optional. With no provider, every result carries an empty message set and the library behaves as it did before messages existed.
docs/MESSAGES.md covers writing a pack, the specificity ladder, and using a format other than MF2.
Field types
Nineteen, each parsing to its own value object:
Address · Boolean · Collection · CreditCard · Date · DateTime · Duration ·
EmailAddress · Enum · File · Money · Name · Number · Password · PhoneNumber ·
Text · Time · Uri · Uuid
docs/COOKBOOK.md has the common form patterns as one snippet each.
The domain types are the point: an Address validates against Google's libaddressinput, a
PhoneNumber against libphonenumber, a Password against zxcvbn.
Declare a region once and the region-aware fields inherit it:
Rules
One field's value deciding another's requirements. Both branches live on the same rule, so they cannot drift apart:
An outcome is the field, configured. There is no thenRequire() and there never needs to
be one: you call the field's own withers and the rule records what changed. So every
configuration method a field has is already a rule outcome — including on a field type you
wrote yourself:
It is type-safe because the field is on the left: $terms is a Boolean, so
mustBeAccepted() is on it and minLengthOf() is not, and your editor knows both. Fields
are immutable, so the wither hands back a copy and the schema's own field is untouched.
Twelve matchers, and the inclusive ones say so in their names:
A field offers only the questions its value can answer. $notes is text, so its matcher
carries contains and matches and no ordering at all — $notes->when()->isAtLeast(3) is a
call to a method that is not there, greyed out in your editor before you run anything. The
ordered questions belong to numbers, dates, times, durations and money.
$schema->when('age') still works for a field named by string or a scope pointing at a part.
It cannot know the type, so it offers all twelve and leans on the check that runs when the
rule is added.
A rule can compare two fields, whole or part by part:
Rules are checked when they are written, not when they fire — a field that does not exist, a
part that is misspelled, or a value the target field could never hold all raise at addRule().
The result says which rules acted, so a renderer can tell a rule-driven optional from an authored one:
Concurrency
A schema is a definition and nothing per-request touches it, so one instance serves many requests:
Fields are readonly, the field and rule sets are private(set), and a per-request value is
passed in rather than stored. Per-user data arrives with the request too, so a serialized schema
can never contain it:
tests/LongLivedProcessTest.php interleaves two requests with fibres to prove it.
Documentation
docs/ is the index. The short version:
- DESIGN.md — the decisions and what each costs
- API.md — every field's surface
- EXTENDING.md — writing your own field type
- COMPARISON.md — the alternatives, fairly
- LIMITATIONS.md — what is still wrong
- DEVELOPER.md — contributing to the core itself
- examples/ — fourteen runnable examples, one aspect each
Testing
composer ci also runs every example and checks the changelog is current. An example that stops
working fails the build — documentation that does not run is worse than none.
License
MIT. See LICENSE.
All versions of schema with dependencies
brick/date-time Version ^0.7.0
brick/math Version ^0.12.1
brick/money Version ^0.11.0
commerceguys/addressing Version ^2.0
giggsey/libphonenumber-for-php-lite Version ^8.13
bjeavons/zxcvbn-php Version ^1.4