oihana/php-schema

The Oihana PHP Schema library

Maintainers

Package info

github.com/BcommeBois/oihana-php-schema

pkg:composer/oihana/php-schema

Statistics

Installs: 404

Dependents: 12

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.1 2025-10-30 08:07 UTC

This package is auto-updated.

Last update: 2026-05-26 15:14:32 UTC


README

Oihana PHP Schema

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.

Latest Version
Total Downloads
License

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"
  }
}

๐Ÿ—‚๏ธ Schemas overview

The library exposes three top-level namespaces. Each row below links to a dedicated wiki guide (English / Franรงais) that lists the classes, gives a code example and points to the source.

Namespace What it covers Classes Wiki guide
org\schema Full Schema.org vocabulary โ€” typed value objects for Thing, Person, Place, Event, Product, Offer, the complete Action hierarchy, creative works, organizations, services, enumerations. ~400 ๐Ÿ‡ฌ๐Ÿ‡ง EN ยท ๐Ÿ‡ซ๐Ÿ‡ท FR
xyz\oihana\schema\auth OAuth2/OIDC clients, sessions, keyfiles, users, roles, permissions, RBAC policies, Casbin helpers, JWT claims registry. 15 ๐Ÿ‡ฌ๐Ÿ‡ง EN ยท ๐Ÿ‡ซ๐Ÿ‡ท FR
xyz\oihana\schema\places Operational locations: Site, Office, Warehouse, JobSite. 4 ๐Ÿ‡ฌ๐Ÿ‡ง EN ยท ๐Ÿ‡ซ๐Ÿ‡ท FR
xyz\oihana\schema Cross-cutting Oihana types: Pagination, Log, AuditAction, audit enumerations. 3 + enums ๐Ÿ‡ฌ๐Ÿ‡ง EN ยท ๐Ÿ‡ซ๐Ÿ‡ท FR
com\progress\schema OpenEdge Progress SQL SYS% system catalog: tables, columns, indexes, views, users, privileges, constraints, sequences, triggers, procedures, data types. 16 ๐Ÿ‡ฌ๐Ÿ‡ง EN ยท ๐Ÿ‡ซ๐Ÿ‡ท FR

Every entity extends org\schema\Thing, so they all share the same JSON-LD serialization, hydration and ArangoDB metadata. Sub-namespaces override the CONTEXT constant so downstream consumers can tell them apart:

Namespace JSON-LD @context
org\schema https://schema.org
xyz\oihana\schema* https://schema.oihana.xyz
com\progress\schema https://schema.progress.com

๐Ÿง  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

Two complementary sets of documentation are available:

While the wiki grows, you can also explore the following namespaces directly:

  • org\schema\ for value objects
  • org\schema\traits for logic traits
  • org\schema\constants for property constants

โœ… 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

๐Ÿ› ๏ธ 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 and oihana/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.

๐Ÿค 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

โ“ 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 under schemas/ 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 whose items use a oneOf of the non-array types (here ImageObject and string).