oihana / php-schema
The Oihana PHP Schema library
Installs: 134
Dependents: 6
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/oihana/php-schema
Requires
- php: >=8.4
- oihana/php-core: dev-main
- oihana/php-reflect: dev-main
Requires (Dev)
- nunomaduro/collision: ^8.8
- phpdocumentor/shim: ^3.8
- phpunit/phpunit: ^12
README
Oihana Schema is a PHP library that provides an object-oriented implementation of the Schema.org vocabulary. It is designed to encapsulate structured data using strongly typed value objects, with automatic serialization and hydration features.
This library is ideal for representing database records or REST API resources in a structured, semantically rich way, compatible with JSON-LD and linked data ecosystems.
โจ Key Features
- โ๏ธ Full modeling of Schema.org entities
- ๐งฉ Automatic JSON-LD serialization (JsonSerializable)
- ๐ช Recursive object hydration (including nested types and union types)
- ๐ง Internal reflection system (oihana\reflections)
- ๐ฏ Safe property access via constants (e.g. Schema::NAME)
- ๐ Extensible architecture for custom ontologies
- ๐ Support for ArangoDB metadata (_id, _key, _rev, _from, _to)
๐ฆ Installation
Requires PHP 8.4+
Install via Composer:
composer require oihana/php-schema
๐ Quick Example
Simple usage
use org\schema\Person; use org\schema\PostalAddress; use org\schema\constants\Schema; $person = new Person ([ Schema::ID => '2555', Schema::NAME => 'John Doe', Schema::ADDRESS => new PostalAddress ([ Schema::STREET_ADDRESS => '2 chemin des Vergers', Schema::POSTAL_CODE => '49170' ]) ]); echo json_encode( $person , JSON_PRETTY_PRINT ) ;
JSON-LD output
{ "@type": "Person", "@context": "https://schema.org", "id": "2555", "name": "John Doe", "address": { "@type": "PostalAddress", "@context": "https://schema.org", "streetAddress": "2 chemin des Vergers", "postalCode": "49170" } }
๐ง Internal Architecture
Base class: Thing
All entities extend the base class org\schema\Thing, which includes common Schema.org and metadata properties, as well as serialization logic:
The ThingTrait handles:
- Dynamic constructor from arrays or objects
- JSON-LD serialization via jsonSerialize()
- Reflection-based helpers from ReflectionTrait
Recursive Hydration
The internal Reflection::hydrate() method builds full object graphs from associative arrays, including nested value objects and union types:
$person = $reflection->hydrate ([ 'name' => 'Alice', 'address' => [ 'streetAddress' => '123 Lilac Street' ] ], Person::class ) ;
๐ Safe Property Access
The org\schema\constants\Schema class contains constant names for every property in the Schema.org ontology and its extensions:
use org\schema\constants\Schema; use org\schema\Event; $event = new Event ([ Schema::NAME => 'Oihana Conf 2025', Schema::LOCATION => new Place([ Schema::NAME => 'Nantes' ]) ]);
Properties are grouped by logical trait namespaces (e.g. Thing, Person, Event, etc.) for auto-completion and modularity:
trait Thing { const string NAME = 'name'; const string URL = 'url'; const string ID = 'id'; // ... }
๐ Documentation
Full project documentation is available at:
๐ https://bcommebois.github.io/oihana-php-schema
A complete developer guide will be available soon, including:
- UML diagrams
- Object maps and relationships
- Auto-generated property references
In the meantime, explore the following namespaces:
- org\schema\ for value objects
- org\schema\traits for logic traits
- org\schema\constants for property constants
๐ซ๐ท xyz\oihana Namespace (oihana.xyz extensions)
In addition to the Schema.org core under org\\schema
, this library provides an extension namespace for Oihana-specific needs used in the ecosystem: xyz\\oihana\\schema
.
What you will find there:
- Value objects for domain-specific concepts (e.g.,
xyz\\oihana\\schema\\Pagination
). - A constants container
xyz\\oihana\\schema\\constants\\Oihana
exposing safe property names via traits (e.g.,Pagination
constants).
Example: model pagination parameters with JSON-LD support
use xyz\oihana\schema\Pagination; use xyz\oihana\schema\constants\Oihana; $pagination = new Pagination ([ Oihana::LIMIT => 50, Oihana::PAGE => 2, ]); // JSON-LD with a dedicated context for Oihana extensions echo json_encode($pagination, JSON_UNESCAPED_SLASHES); // {"@type":"Pagination","@context":"https://schema.oihana.xyz","limit":50,"page":2}
Key points:
Pagination
extendsorg\schema\Intangible
and integrates seamlessly with the rest of the model.Pagination::CONTEXT
defaults tohttps://schema.oihana.xyz
to distinguish Oihana extensions.- Use
xyz\oihana\schema\constants\Oihana
to reference property names safely:Oihana::LIMIT
,Oihana::OFFSET
,Oihana::MAX_LIMIT
,Oihana::MIN_LIMIT
,Oihana::NUMBER_OF_PAGES
,Oihana::PAGE
.
โ Running Unit Tests
To run all tests:
composer test
To run a specific test file:
composer test ./tests/org/schema/ThingTest.php composer test ./tests/xyz/oihana/schema/PaginationTest.php
๐งพ License
This project is licensed under the Mozilla Public License 2.0 (MPL-2.0).
๐ค About the author
- Author : Marc ALCARAZ (aka eKameleon)
- Mail : marc@ooop.fr
- Website : http://www.ooop.fr
๐ ๏ธ Generate the Documentation
We use phpDocumentor to generate the documentation into the ./docs folder.
Usage
Run the command :
composer doc
๐งฉ Advanced Usage
Union-typed properties
Some properties accept multiple types. For instance, publisher
may be a string
, a Person
, or an Organization
.
use org\schema\CreativeWork; use org\schema\Person; use org\schema\Organization; use org\schema\constants\Schema; $post = new CreativeWork ([ Schema::NAME => 'Release Notes', Schema::PUBLISHER => new Organization([ Schema::NAME => 'Oihana' ]) ]);
Arrays and nested entities
You can compose objects with arrays of other entities, leveraging the public-typed properties.
use org\schema\Thing; use org\schema\constants\Schema; $parent = new Thing ([ Schema::NAME => 'Bundle', Schema::HAS_PART => [ new Thing([ Schema::NAME => 'Part A' ]), new Thing([ Schema::NAME => 'Part B' ]), ], ]);
JSON-LD metadata for ArangoDB
Base Thing
supports ArangoDB-style metadata fields to facilitate graph storage:
_key
, _id
, _rev
, _from
, _to
.
use org\schema\Thing; $edge = new Thing ([ '_from' => 'users/2555', '_to' => 'groups/42', ]);
Deep/recursive hydration
The constructor copies provided values into public properties.
For deep graphs and automatic casting, you can rely on the internal reflection utilities exposed by oihana/php-reflect
(see developer docs). A typical approach is to call a reflection-based hydrate()
to materialize nested arrays into value objects.
๐งฑ Extending the Library
Define your own types by extending org\schema\Thing
or a more specific class, and add your public-typed properties. You can also define constants alongside org\schema\constants\Schema
for safer access.
namespace app\domain; use org\schema\Thing; class CustomAsset extends Thing { public ?string $slug; public ?string $category; }
โ๏ธ Installation Notes
- This package requires PHP 8.4+.
- It depends on
oihana/php-core
andoihana/php-reflect
. If your project enforces stable versions only, you may need to allow dev versions while these libraries are pre-release:- In your root composer.json: set
"minimum-stability": "dev"
and"prefer-stable": true
if needed.
- In your root composer.json: set
๐ค Contributing
Contributions are welcome! Please:
- Open an issue to discuss significant changes before submitting a PR.
- Add tests when fixing a bug or adding a feature.
- Keep code style consistent and types explicit.
Local setup:
composer install
composer test
composer doc
๐ Security
If you discover a security vulnerability, please email marc@ooop.fr
. Do not open a public issue for security reports.
๐ Changelog
See CHANGELOG.md
for notable changes.
๐ Related Packages
- oihana/php-core โ core helpers and utilities used by this library
- oihana/php-reflect โ reflection and hydration utilities
โ FAQ
- Why JSON-LD?
Itโs a web-native, schema-friendly format that plays well with linked data and search engines. - Can I output plain arrays?
Yes,jsonSerialize()
returns arrays that you can pass to any JSON encoder. - How to ignore nulls?
Serialization automatically removes null values.
๐งฎ JSON Schema Generation
Generate JSON Schemas from the typed public properties of your classes.
- Single class (example: Place):
composer schema:place
- All classes under
src/org/schema
:
composer schemas:all
Details:
- Schemas are written to
schemas/*.schema.json
. - Union types are represented as
oneOf
; class types are emitted as$ref
into local$defs
. - Requires Composer autoload (run
composer dump-autoload -o
if classes are not found).
Output layout and cleanup
- Namespaces map to folders under
schemas/
:org\schema\...
โschemas/org/schema/.../*.schema.json
xyz\oihana\schema\...
โschemas/xyz/oihana/schema/.../*.schema.json
- Running
composer schemas:all
first deletes previous*.schema.json
underschemas/
to avoid stale files, then regenerates everything.
Array unions handling
When a property type includes array
plus other types (e.g. string|ImageObject|array<ImageObject|string>|null
), the generator emits:
- direct options for
string
,ImageObject
,null
(if present) - and an
array
variant whoseitems
use aoneOf
of the non-array types (hereImageObject
andstring
).