Skip to content

Commit

Permalink
Use separate class for work on Schema
Browse files Browse the repository at this point in the history
  • Loading branch information
trasher committed Jan 21, 2025
1 parent da016b3 commit da04849
Show file tree
Hide file tree
Showing 4 changed files with 490 additions and 369 deletions.
207 changes: 10 additions & 197 deletions lib/php/Converter.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
use DateTime;
use Exception;
use RuntimeException;
use Swaggest\JsonSchema\Context;
use Swaggest\JsonSchema\Schema;
use UnexpectedValueException;

/**
Expand All @@ -31,6 +29,7 @@ class Converter
/** @var ?float */
private ?float $target_version;

private Schema $schema;
/** @var bool */
private bool $debug = false;
/**
Expand Down Expand Up @@ -85,6 +84,7 @@ class Converter
*/
public function __construct($target_version = null)
{
$this->schema = new Schema();
if ($target_version === null) {
$target_version = self::LAST_VERSION;
}
Expand Down Expand Up @@ -130,144 +130,23 @@ public function isDebug(): bool
}

/**
* Get path to schema
* Get Schema instance
*
* @return string
* @return Schema
*/
public function getSchemaPath(): string
public function getSchema(): Schema
{
$schema_path = realpath(__DIR__ . '/../../inventory.schema.json');
if ($schema_path === false) {
throw new RuntimeException('Schema file not found!');
}
return $schema_path;
return $this->schema;
}

/**
* Add extra properties to schema
* Get JSON schema
*
* @param array<string, array<string, string>> $properties
* @return $this
* @return object
*/
public function setExtraProperties(array $properties): self
public function getJSONSchema(): object
{
$this->extra_properties = $properties;
return $this;
}

/**
* Add extra sub-properties to schema
*
* @param array<string, array<string, array<string, string>>> $properties
* @return $this
*/
public function setExtraSubProperties(array $properties): self
{
$this->extra_sub_properties = $properties;
return $this;
}

/**
* Add new supported item types
*
* @param array<string> $itemtypes
* @return $this
*/
public function setExtraItemtypes(array $itemtypes): self
{
$this->extra_itemtypes = $itemtypes;
return $this;
}

/**
* Build (extended) JSON schema
*
* @return mixed
*/
public function buildSchema()
{
$string = file_get_contents($this->getSchemaPath());
if ($string === false) {
throw new RuntimeException('Unable to read schema file');
}
$schema = json_decode($string);

$known_itemtypes = [];
preg_match('/\^\((.+)\)\$/', $schema->properties->itemtype->pattern, $known_itemtypes);
if (isset($known_itemtypes[1])) {
$known_itemtypes = explode('|', $known_itemtypes[1]);
foreach ($this->extra_itemtypes as $extra_itemtype) {
if (!in_array($extra_itemtype, $known_itemtypes)) {
$known_itemtypes[] = addslashes($extra_itemtype);
}
}
$schema->properties->itemtype->pattern = sprintf(
'^(%s)$',
implode('|', $known_itemtypes)
);
}

$properties = $schema->properties->content->properties;

foreach ($this->extra_properties as $extra_property => $extra_config) {
if (!property_exists($properties, $extra_property)) {
$properties->$extra_property = json_decode((string)json_encode($extra_config));
} else {
trigger_error(
sprintf('Property %1$s already exists in schema.', $extra_property),
E_USER_WARNING
);
}
}

foreach ($this->extra_sub_properties as $extra_sub_property => $extra_sub_config) {
if (property_exists($properties, $extra_sub_property)) {
foreach ($extra_sub_config as $subprop => $subconfig) {
$type = $properties->$extra_sub_property->type;
switch ($type) {
case 'array':
if (!property_exists($properties->$extra_sub_property->items->properties, $subprop)) {
$properties->$extra_sub_property->items->properties->$subprop =
json_decode((string)json_encode($subconfig));
} else {
trigger_error(
sprintf('Property %1$s already exists in schema.', $subprop),
E_USER_WARNING
);
}
break;
case 'object':
if (!property_exists($properties->$extra_sub_property->properties, $subprop)) {
$properties->$extra_sub_property->properties->$subprop =
json_decode((string)json_encode($subconfig));
} else {
trigger_error(
sprintf(
'Property %1$s/%2$s already exists in schema.',
$extra_sub_property,
$subprop
),
E_USER_WARNING
);
}
break;
default:
trigger_error('Unknown type ' . $type, E_USER_WARNING);
}
}
} else {
trigger_error(
sprintf('Property %1$s does not exists in schema.', $extra_sub_property),
E_USER_WARNING
);
}
}

if ($this->strict_schema === false) {
$this->buildFlexibleSchema($schema->properties->content);
}

return $schema;
return $this->schema->buildSchema();
}

/**
Expand Down Expand Up @@ -1169,7 +1048,6 @@ public function convertTypes(array &$data): void
}
}


/**
* Get value casted
*
Expand Down Expand Up @@ -1257,29 +1135,6 @@ public function convertDate(string $value, string $format = 'Y-m-d'): ?string
return $value;
}

/**
* Load schema patterns that will be used to validate
*
* @return void
*/
public function loadSchemaPatterns(): void
{
$string = file_get_contents($this->getSchemaPath());
if ($string === false) {
throw new RuntimeException('Unable to read schema file');
}
$json = json_decode($string, true);

$this->schema_patterns['networks_types'] = explode(
'|',
str_replace(
['^(', ')$'],
['', ''],
$json['properties']['content']['properties']['networks']['items']['properties']['type']['pattern']
)
);
}

/**
* Convert battery capacity
*
Expand Down Expand Up @@ -1774,46 +1629,4 @@ private function isNetworkDiscovery(array $data): bool
{
return isset($data['content']['device']) && $data['action'] == 'netdiscovery';
}

/**
* Set schema validation strict (no additional properties allowed anywhere)
*
* @return self
*/
public function setStrictSchema(): self
{
$this->strict_schema = true;
return $this;
}

/**
* Set schema validation strict (no additional properties allowed anywhere)
*
* @return self
*/
public function setFlexibleSchema(): self
{
$this->strict_schema = false;
return $this;
}

/**
* Build schema flexible (remove all additionalProperties)
*
* @param mixed $schemapart
*
* @return void
*/
private function buildFlexibleSchema(&$schemapart)
{
foreach ($schemapart as $key => $value) {
if (is_object($value) || is_array($value)) {
$this->buildFlexibleSchema($value);
} else {
if ($key == 'additionalProperties') {
unset($schemapart->$key);
}
}
}
}
}
Loading

0 comments on commit da04849

Please sign in to comment.