Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: PHP SDK

on:
push:
branches: [master, main]
paths:
- 'php/**'
- '.github/workflows/php.yml'
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
pull_request:
branches: [master, main]
paths:
- 'php/**'
- '.github/workflows/php.yml'

permissions:
contents: read

jobs:
test:
name: Test PHP ${{ matrix.php-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-version: ['8.1', '8.2', '8.3']

steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Set up PHP ${{ matrix.php-version }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
extensions: bcmath, json, mbstring
coverage: xdebug

- name: Validate composer.json
working-directory: php
run: composer validate --strict

- name: Install dependencies
working-directory: php
run: composer install --prefer-dist --no-progress

- name: Run tests
working-directory: php
run: vendor/bin/phpunit --coverage-text --coverage-clover=coverage.xml

- name: Upload coverage reports
if: matrix.php-version == '8.2'
uses: codecov/codecov-action@v4
with:
file: php/coverage.xml
flags: php
fail_ci_if_error: false
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,7 @@ TestResults/
*.trx
nupkg/
go/coverage

# PHP
php/vendor/
php/composer.lock
255 changes: 255 additions & 0 deletions php/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
# JSON Structure PHP SDK

A PHP SDK for JSON Structure schema and instance validation.

## Requirements

- PHP 8.1 or higher
- BCMath extension (for large integer validation)
- JSON extension

## Installation

### Via Composer

```bash
composer require json-structure/sdk
```

### Manual Installation

Clone the repository and run:

```bash
cd php
composer install
```

## Usage

### Schema Validation

Validate a JSON Structure schema document:

```php
<?php

use JsonStructure\SchemaValidator;

$schema = [
'$id' => 'https://example.com/person.struct.json',
'$schema' => 'https://json-structure.org/meta/core/v0/#',
'name' => 'Person',
'type' => 'object',
'properties' => [
'name' => ['type' => 'string'],
'age' => ['type' => 'int32'],
'email' => ['type' => 'string']
],
'required' => ['name']
];

$validator = new SchemaValidator(extended: true);
$errors = $validator->validate($schema);

if (count($errors) === 0) {
echo "Schema is valid!\n";
} else {
echo "Schema validation errors:\n";
foreach ($errors as $error) {
echo " - " . $error . "\n";
}
}
```

### Instance Validation

Validate a JSON instance against a JSON Structure schema:

```php
<?php

use JsonStructure\InstanceValidator;

$schema = [
'$id' => 'https://example.com/person.struct.json',
'$schema' => 'https://json-structure.org/meta/core/v0/#',
'name' => 'Person',
'type' => 'object',
'properties' => [
'name' => ['type' => 'string'],
'age' => ['type' => 'int32'],
'email' => ['type' => 'string']
],
'required' => ['name']
];

$instance = [
'name' => 'John Doe',
'age' => 30,
'email' => 'john@example.com'
];

$validator = new InstanceValidator($schema, extended: true);
$errors = $validator->validate($instance);

if (count($errors) === 0) {
echo "Instance is valid!\n";
} else {
echo "Instance validation errors:\n";
foreach ($errors as $error) {
echo " - " . $error . "\n";
}
}
```

### Extended Validation

Enable extended validation features (conditional composition, validation keywords):

```php
<?php

use JsonStructure\SchemaValidator;
use JsonStructure\InstanceValidator;

$schema = [
'$id' => 'https://example.com/user.struct.json',
'$schema' => 'https://json-structure.org/meta/core/v0/#',
'$uses' => ['JSONStructureValidation'],
'name' => 'User',
'type' => 'object',
'properties' => [
'username' => [
'type' => 'string',
'minLength' => 3,
'maxLength' => 20,
'pattern' => '^[a-zA-Z][a-zA-Z0-9_]*$'
],
'age' => [
'type' => 'int32',
'minimum' => 0,
'maximum' => 150
]
],
'required' => ['username']
];

// Validate schema
$schemaValidator = new SchemaValidator(extended: true);
$schemaErrors = $schemaValidator->validate($schema);

if (count($schemaErrors) > 0) {
echo "Schema errors: " . count($schemaErrors) . "\n";
}

// Validate instance
$instance = [
'username' => 'johndoe',
'age' => 30
];

$instanceValidator = new InstanceValidator($schema, extended: true);
$instanceErrors = $instanceValidator->validate($instance);

if (count($instanceErrors) === 0) {
echo "Valid!\n";
}
```

## Supported Types

### Primitive Types (34)

| Type | Description |
|------|-------------|
| `string` | UTF-8 string |
| `boolean` | `true` or `false` |
| `null` | Null value |
| `number` | Any JSON number |
| `integer` | Alias for `int32` |
| `int8` | -128 to 127 |
| `int16` | -32,768 to 32,767 |
| `int32` | -2³¹ to 2³¹-1 |
| `int64` | -2⁶³ to 2⁶³-1 (as string) |
| `int128` | -2¹²⁷ to 2¹²⁷-1 (as string) |
| `uint8` | 0 to 255 |
| `uint16` | 0 to 65,535 |
| `uint32` | 0 to 2³²-1 |
| `uint64` | 0 to 2⁶⁴-1 (as string) |
| `uint128` | 0 to 2¹²⁸-1 (as string) |
| `float8` | 8-bit float |
| `float` | 32-bit IEEE 754 |
| `double` | 64-bit IEEE 754 |
| `decimal` | Arbitrary precision (as string) |
| `date` | RFC 3339 date (`YYYY-MM-DD`) |
| `time` | RFC 3339 time (`HH:MM:SS[.sss]`) |
| `datetime` | RFC 3339 datetime |
| `duration` | ISO 8601 duration |
| `uuid` | RFC 9562 UUID |
| `uri` | RFC 3986 URI |
| `binary` | Base64-encoded bytes |
| `jsonpointer` | RFC 6901 JSON Pointer |

### Compound Types

| Type | Description |
|------|-------------|
| `object` | JSON object with typed properties |
| `array` | Homogeneous list |
| `set` | Unique homogeneous list |
| `map` | Dictionary with string keys |
| `tuple` | Fixed-length typed array |
| `choice` | Discriminated union |
| `any` | Any JSON value |

## Error Handling

All validation errors use standardized error codes:

```php
<?php

use JsonStructure\ErrorCodes;

// Schema validation errors start with SCHEMA_
ErrorCodes::SCHEMA_TYPE_INVALID;
ErrorCodes::SCHEMA_REF_NOT_FOUND;
ErrorCodes::SCHEMA_REQUIRED_PROPERTY_NOT_DEFINED;

// Instance validation errors start with INSTANCE_
ErrorCodes::INSTANCE_TYPE_MISMATCH;
ErrorCodes::INSTANCE_REQUIRED_PROPERTY_MISSING;
ErrorCodes::INSTANCE_ENUM_MISMATCH;
```

Each `ValidationError` includes:
- `code`: Standardized error code
- `message`: Human-readable error message
- `path`: JSON Pointer path to the error location
- `severity`: `ERROR` or `WARNING`
- `location`: Line/column position (when source text is available)

## Testing

Run the test suite:

```bash
composer test
```

Run tests with coverage:

```bash
composer test-coverage
```

## License

MIT License - see [LICENSE](../LICENSE) for details.

## Related Resources

- [JSON Structure Specification](https://json-structure.github.io/core/)
- [SDK Guidelines](../SDK-GUIDELINES.md)
- [Test Assets](../test-assets/)
44 changes: 44 additions & 0 deletions php/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "json-structure/sdk",
"description": "Validators for JSON Structure schemas and instances",
"type": "library",
"license": "MIT",
"keywords": [
"json",
"schema",
"validation",
"json-structure",
"type-system"
],
"homepage": "https://json-structure.org",
"authors": [
{
"name": "JSON Structure Project",
"email": "info@json-structure.org"
}
],
"require": {
"php": ">=8.1"
},
"require-dev": {
"phpunit/phpunit": "^10.0 || ^11.0"
},
"autoload": {
"psr-4": {
"JsonStructure\\": "src/JsonStructure/"
}
},
"autoload-dev": {
"psr-4": {
"JsonStructure\\Tests\\": "tests/"
}
},
"scripts": {
"test": "phpunit",
"test-coverage": "phpunit --coverage-text --coverage-clover=coverage.xml"
},
"config": {
"sort-packages": true
},
"minimum-stability": "stable"
}
Loading