JVal
JVal copied to clipboard
Resolver relies on getPrimaryResourceIdentifier() being unique for each schema
Resolver relies e.g. in registerSchema on getPrimaryResourceIdentifier being unique for each schema however when Validator::validate is called without the third argument, the getPrimaryResourceIdentifier() returns empty string every time.
My guess is that we must either make the 3rd parameter of Validator::validate required or generate primary resource identifier differently (maybe random?) when empty Uri is passed.
Maybe we can just put sth like this to Validator::validate
if ($schemaUri === '') {
$schemaUri = '/schema/' . md5(spl_object_hash($schema));
}
Unless a $ref pointing to another document is encountered, we never leave the current schema, so it's expected to get always the same identifier (here the empty string) and the same schema from the cache. If an external $ref is met, the identifier returned by getPrimaryResourceIdentifier() must be different. Isn't this the case? Can you provide a schema illustrating the issue?
I guess you're right. The registerSchema behavior is wrong (relying on uniqueness of primary resource identifier even when it's empty string), but resolve does never actually read those schemas with empty identifier so it never actually breaks anything.
Therefore the best solution would likely be to just ignore empty identifiers in registerSchema as caching them is both wrong and pointless.
$id = $uri->getPrimaryResourceIdentifier();
if ($id !== '' && !isset($this->schemas[$id])) {
$this->schemas[$id] = $schema;
}
The registerSchema behavior is wrong (relying on uniqueness of primary resource identifier even when it's empty string)
I don't agree. The empty string is also a valid identifier. It's unique and will always denote the document from which we started, in case no path/url was provided.
resolve does never actually read those schemas
It will when a solution will be provided for #6.
The collision with #6 is a good observation.
It's unique and will always denote the document from which we started
When you call validate with schema A without URL and then validate with schema B without URL, references such as {"$ref": "#"} in schema B would resolve against schema A.
You're right, and actually even for #6, the schema should probably be taken from $stack and not $schemas, so we can safely exclude the empty string as you suggested.
What about implementing check in registerSchema to prevent accidental overrides
public function registerSchema(stdClass $schema, Uri $uri)
{
$identifier = $uri->getPrimaryResourceIdentifier();
if ($identifier === '') {
// ignore
} elseif (!isset($this->schemas[$identifier])) {
$this->schemas[$identifier] = $schema;
} elseif ($this->schemas[$identifier] != $schema) { // intentionally ==, instead of ===
throw new \LogicException('Different schema is already registered with given URI.');
}
}