Skip to content
Merged
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
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: CI

on:
push:
branches: [ main, master ]
pull_request: {}

jobs:
tests:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php-version: ['8.1', '8.2', '8.3', '8.4']

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
coverage: none

- name: Install dependencies
run: composer install --prefer-dist --no-interaction --no-progress

- name: Run test suite
run: composer test
13 changes: 11 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "phindmarsh/statham",
"name": "wave-framework/statham",
"description": "A JSON Schema validator",
"minimum-stability": "stable",
"license": "MIT",
Expand All @@ -9,9 +9,18 @@
"email": "patrick@hindmar.sh"
}
],
"require": {
"php": "^8.1 || ^8.2 || ^8.3 || ^8.4"
},
"require-dev": {
"phpunit/phpunit": "^10.5"
},
"scripts": {
"test": "phpunit"
},
"autoload": {
"psr-4": {
"Statham\\": "src/"
}
}
}
}
11 changes: 11 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
colors="true"
failOnRisky="true"
failOnWarning="true">
<testsuites>
<testsuite name="Statham Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
</phpunit>
25 changes: 17 additions & 8 deletions src/Json/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@

class Validator {

private $rootSchema;
private $statham;
private ?object $rootSchema = null;
private Statham $statham;

public function __construct(Statham $statham) {
$this->statham = $statham;
Expand All @@ -21,7 +21,7 @@ public function isMultipleOf(Report $report, $schema, $json){
if(!is_numeric($json))
return;

if($json % $schema->multipleOf !== 0){
if(!Utils::isMultipleOf($json, $schema->multipleOf)){
$report->addError('MULTIPLE_OF', [$json, $schema->multipleOf], null, $schema);
}
}
Expand Down Expand Up @@ -214,6 +214,10 @@ public function isDependencies(Report $report, $schema, $json){
if(!is_object($json))
return;

if(!isset($schema->dependencies) || !is_iterable($schema->dependencies)){
return;
}

foreach($schema->dependencies as $depencencyName => $depencencyDefinition){
if(isset($json->$depencencyName)) {
if(is_object($depencencyDefinition)){
Expand Down Expand Up @@ -309,6 +313,7 @@ public function validate(Report $report, $schema, $json){

if(!is_object($schema)){
$report->addError('SCHEMA_NOT_AN_OBJECT', [gettype($schema)], null, $schema);
return false;
}

// anything is valid against an empty schema
Expand All @@ -317,7 +322,7 @@ public function validate(Report $report, $schema, $json){
}

$isRoot = false;
if(!isset($this->rootSchema)){
if($this->rootSchema === null){
$this->rootSchema = $schema;
$isRoot = true;
}
Expand Down Expand Up @@ -369,7 +374,7 @@ public function validate(Report $report, $schema, $json){
}

if($isRoot){
unset($this->rootSchema);
$this->rootSchema = null;
}

return $report->isValid();
Expand Down Expand Up @@ -414,8 +419,12 @@ private function recurseObject(Report $report, $schema, $json){
if($additionalProperties === true)
$additionalProperties = new \stdClass();

$properties = isset($schema->properties) ? $schema->properties : new \stdClass();
$patternProperties = isset($schema->patternProperties) ? $schema->patternProperties : new \stdClass();
if(!is_object($additionalProperties) && $additionalProperties !== false){
$additionalProperties = new \stdClass();
}

$properties = (isset($schema->properties) && is_object($schema->properties)) ? $schema->properties : new \stdClass();
$patternProperties = (isset($schema->patternProperties) && is_object($schema->patternProperties)) ? $schema->patternProperties : new \stdClass();

foreach($json as $m => $propertyValue){

Expand Down Expand Up @@ -443,4 +452,4 @@ private function recurseObject(Report $report, $schema, $json){
}
}

}
}
2 changes: 1 addition & 1 deletion src/Report.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Report {
public $errors = [];
private $path = [];

public function __construct(Report $parent = null, array $options = []){
public function __construct(Report|null $parent, array $options = []){

if($parent instanceof Report){
$this->parent = $parent;
Expand Down
20 changes: 12 additions & 8 deletions src/Schema/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
class Cache {

/** @var Statham */
private $statham;
private Statham $statham;
/** @var array */
private $cache = [];
private array $cache = [];
/** @var array */
private $referenceCache = [];
private array $referenceCache = [];

public function __construct(Statham $statham){
$this->statham = $statham;
Expand Down Expand Up @@ -116,17 +116,21 @@ private function decodeJSONPointer($str) {

private function findId($schema, $id){

if(!is_object($schema)){
return null;
}

if(!$id)
return $schema;

if(isset($schema->id)){
if($schema->id === $id || $schema->id[0] === '#' && substr($schema->id, 1) === $id){
if(isset($schema->id) && is_string($schema->id)){
if($schema->id === $id || str_starts_with($schema->id, '#' . $id)){
return $schema;
}
}

$keys = get_object_vars($schema);
for($i = count($keys); $i >= 0; $i--){
$keys = array_keys(get_object_vars($schema));
for($i = count($keys) - 1; $i >= 0; $i--){
$k = $keys[$i];
if(strpos($k, '__$') !== false)
continue;
Expand All @@ -141,4 +145,4 @@ private function findId($schema, $id){



}
}
4 changes: 2 additions & 2 deletions src/Schema/Compiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

class Compiler {

protected $statham;
protected Statham $statham;

public function __construct(Statham $statham){
$this->statham = $statham;
Expand Down Expand Up @@ -231,4 +231,4 @@ private function mergeReference($scope, $ref){
return preg_replace('/##/', '#', $joinedScope . $ref);
}

}
}
58 changes: 31 additions & 27 deletions src/Schema/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class Validator {
'default' => []
];

private Statham $statham;

public function __construct(Statham $statham){
$this->statham = $statham;
}
Expand Down Expand Up @@ -186,36 +188,36 @@ public function isRequired(Report $report, $schema, $key){
}

public function isDependencies(Report $report, $schema, $key){
if(!is_object($schema)){
if(!isset($schema->$key) || !is_object($schema->$key)){
$report->addError('KEYWORD_TYPE_EXPECTED', [$key, 'object']);
return;
}
else {
foreach($schema->$key as $schemaKey => $schemaDependency){

if(is_object($schemaDependency)){
$report->pathPush($key);
$report->pathPush($schemaKey);
$this->validateSchema($report, $schemaDependency);
$report->pathPop();
$report->pathPop();

foreach($schema->$key as $schemaKey => $schemaDependency){

if(is_object($schemaDependency)){
$report->pathPush($key);
$report->pathPush($schemaKey);
$this->validateSchema($report, $schemaDependency);
$report->pathPop();
$report->pathPop();
}
else if(is_array($schemaDependency)){
if(empty($schemaDependency)){
$report->addError('KEYWORD_MUST_BE', [$key, 'not empty array']);
}
else if(is_array($schemaDependency)){
if(empty($schemaDependency)){
$report->addError('KEYWORD_MUST_BE', [$key, 'not empty array']);
}
foreach($schemaDependency as $i => $value){
if(!is_string($value)){
$report->addError('KEYWORD_VALUE_TYPE', [$key, 'string']);
}
}
if(0 !== count(array_diff($schemaDependency, array_unique($schemaDependency)))){
$report->addError('KEYWORD_MUST_BE', [$key, 'an array with unique items']);
foreach($schemaDependency as $i => $value){
if(!is_string($value)){
$report->addError('KEYWORD_VALUE_TYPE', [$key, 'string']);
}
}
else {
$report->addError('KEYWORD_VALUE_TYPE', [$key, 'object or array']);
if(0 !== count(array_diff($schemaDependency, array_unique($schemaDependency)))){
$report->addError('KEYWORD_MUST_BE', [$key, 'an array with unique items']);
}
}
else {
$report->addError('KEYWORD_VALUE_TYPE', [$key, 'object or array']);
}
}
}

Expand Down Expand Up @@ -319,7 +321,8 @@ public function validateSchema(Report $report, $schema){
if(isset($schema->$validated))
return true;

$hasParentSchema = isset($schema->{'$schema'}) && $schema->id !== $schema->{'$schema'};
$schemaId = property_exists($schema, 'id') ? $schema->id : null;
$hasParentSchema = isset($schema->{'$schema'}) && $schemaId !== $schema->{'$schema'};
if($hasParentSchema){
if(isset($schema->$schemaResolved) && $schema->$schemaResolved !== $schema){
$subReport = new Report($report);
Expand All @@ -339,8 +342,9 @@ public function validateSchema(Report $report, $schema){
//if($statham->options['noTypeless']){
//}

if(!is_array($schema) && !is_object($schema)){
var_dump($schema);
if(!is_object($schema)){
$report->addError('SCHEMA_NOT_AN_OBJECT', [gettype($schema)], null, $schema);
return false;
}

foreach($schema as $key => $value){
Expand Down Expand Up @@ -368,4 +372,4 @@ private function validateArrayOfSchemas(Report $report, $array){
return $report->isValid();
}

}
}
13 changes: 7 additions & 6 deletions src/Statham.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@

class Statham {

public $options = array(
public array $options = array(
// report error paths as an array of path segments to get to the offending node
'reportPathsAsArray' => false,
'ignoreUnresolvableReferences' => false
);

/** @var Cache */
public $cache;
/** @var Report */
public $report;
public Cache $cache;
public Compiler $compiler;
public SchemaValidator $schemaValidator;
public JsonValidator $jsonValidator;
public ?Report $report = null;

public function __construct(array $options = array()){
$this->options = array_merge($this->options, $options);
Expand Down Expand Up @@ -111,4 +112,4 @@ public function setRemoteReference($uri, $schema){
$this->cache->cacheSchemaByUri($uri, $schema);
}

}
}
Loading