[WIP] Hack on serialization

This commit is contained in:
Jeremy Dormitzer 2019-05-26 16:29:48 -04:00
parent 113a26f130
commit 36d16f0352
3 changed files with 94 additions and 64 deletions

View File

@ -6,6 +6,7 @@ use ActivityPub\JsonLd\Dereferencer\DereferencerInterface;
use ActivityPub\JsonLd\Exceptions\NodeNotFoundException; use ActivityPub\JsonLd\Exceptions\NodeNotFoundException;
use ActivityPub\JsonLd\Exceptions\PropertyNotDefinedException; use ActivityPub\JsonLd\Exceptions\PropertyNotDefinedException;
use ActivityPub\JsonLd\TripleStore\TypedRdfTriple; use ActivityPub\JsonLd\TripleStore\TypedRdfTriple;
use ActivityPub\Utils\Util;
use ArrayAccess; use ArrayAccess;
use BadMethodCallException; use BadMethodCallException;
use InvalidArgumentException; use InvalidArgumentException;
@ -136,7 +137,11 @@ class JsonLdNode implements ArrayAccess
{ {
$expandedName = $this->expandName( $name ); $expandedName = $this->expandName( $name );
if ( property_exists( $this->expanded, $expandedName ) ) { if ( property_exists( $this->expanded, $expandedName ) ) {
return $this->resolveProperty( $expandedName, $this->expanded->$expandedName[0] ); $resolved = $this->resolveProperty( $expandedName, $this->expanded->$expandedName[0] );
if ( is_array( $resolved ) ) {
$resolved = $resolved[0];
}
return $resolved;
} }
throw new PropertyNotDefinedException( $name ); throw new PropertyNotDefinedException( $name );
} }
@ -153,7 +158,11 @@ class JsonLdNode implements ArrayAccess
{ {
$expandedName = $this->expandName( $name ); $expandedName = $this->expandName( $name );
if ( property_exists( $this->expanded, $expandedName ) ) { if ( property_exists( $this->expanded, $expandedName ) ) {
return $this->resolveProperty( $expandedName, $this->expanded->$expandedName ); $resolved = $this->resolveProperty( $expandedName, $this->expanded->$expandedName );
if ( ! is_array( $resolved ) ) {
$resolved = array( $resolved );
}
return $resolved;
} }
throw new PropertyNotDefinedException( $name ); throw new PropertyNotDefinedException( $name );
} }
@ -181,10 +190,11 @@ class JsonLdNode implements ArrayAccess
private function resolveProperty( $expandedName, &$property ) private function resolveProperty( $expandedName, &$property )
{ {
if ( is_array( $property ) ) { if ( is_array( $property ) ) {
for ( $i = 0; $i < count( $property); $i += 1) { $properties = [];
$names[] = $expandedName; foreach ( $property as $subProperty ) {
$properties[] = $this->resolveProperty( $expandedName, $subProperty );
} }
return array_map( array( $this, 'resolveProperty'), $names, $property ); return $properties;
} else if ( $property instanceof stdClass && property_exists( $property, '@id') ) { } else if ( $property instanceof stdClass && property_exists( $property, '@id') ) {
// Lazy-load if we only have the @id property // Lazy-load if we only have the @id property
$idProp = '@id'; $idProp = '@id';
@ -201,6 +211,8 @@ class JsonLdNode implements ArrayAccess
} }
return $referencedNode; return $referencedNode;
} else if ( $property instanceof stdClass && property_exists( $property, '@value' ) ) { } else if ( $property instanceof stdClass && property_exists( $property, '@value' ) ) {
// TODO check for an @type and return an appropriate object type if present, e.g. Datetime for dates or
// number for nonNegativeInteger etc.
$value = '@value'; $value = '@value';
return $property->$value; return $property->$value;
} else if ( $property instanceof stdClass ) { } else if ( $property instanceof stdClass ) {
@ -260,7 +272,7 @@ class JsonLdNode implements ArrayAccess
$referencedNode = $this->graph->getNode( $id ); $referencedNode = $this->graph->getNode( $id );
if ( is_null( $referencedNode ) ) { if ( is_null( $referencedNode ) ) {
$backrefs = array( $expandedName => array( $this ) ); $backrefs = array( $expandedName => array( $this ) );
$referencedNode = $this->factory->newNode( $expandedValue, $this->graph, $backrefs ); $this->factory->newNode( $expandedValue, $this->graph, $backrefs );
} else { } else {
$referencedNode->addBackReference( $expandedName, $this ); $referencedNode->addBackReference( $expandedName, $this );
} }
@ -323,7 +335,7 @@ class JsonLdNode implements ArrayAccess
*/ */
public function isBlankNode() public function isBlankNode()
{ {
return property_exists( $this->expanded, '@id' ); return ! property_exists( $this->expanded, '@id' );
} }
/** /**
@ -357,40 +369,39 @@ class JsonLdNode implements ArrayAccess
*/ */
public function toRdfTriples() public function toRdfTriples()
{ {
$cloned = clone $this->expanded; $idProp = '@id';
// First serialize this node $valueProp = '@value';
$quads = JsonLD::toRdf( $cloned ); $typeProp = '@type';
$triples = array(); $triples = array();
foreach ( $quads as $quad ) { foreach ( get_object_vars( $this->expanded ) as $attribute => $values ) {
if ( (string)$quad->getSubject() === $this->getId() ) { if ( ! is_array( $values ) ) {
$objectType = null; // If $values is not an array, this is the @id property
if ( $quad->getObject() instanceof Value ) { $triples[] = TypedRdfTriple::create( $this->getId(), $attribute, $values );
$object = $quad->getObject()->getValue();
if ( $quad->getObject() instanceof TypedValue ) {
$objectType = $quad->getObject()->getType();
}
} else {
$objectIri = $quad->getObject();
if ( $objectIri->getScheme() === '_' ) {
// TODO resolve the associated value to force the generation of a UUID, then set $object to the uuid
} else {
$object = (string)$quad->getObject();
}
$objectType = '@id';
}
$triples[] = TypedRdfTriple::create(
(string)$quad->getSubject(), (string)$quad->getProperty(), $object, $objectType
);
}
}
// Then serialize any sub-nodes
foreach ( $this->expanded as $name => $values ) {
if ( $name === '@id' ) {
continue; continue;
} }
foreach ( $this->getMany( $name ) as $subNode ) { foreach ( $values as $value ) {
if ( $subNode instanceof JsonLdNode ) { if ( ! is_object( $value ) ) {
$triples = array_merge( $triples, $subNode->toRdfTriples() ); // If $value is not an object, this is the @type property
$triples[] = TypedRdfTriple::create( $this->getId(), $attribute, $value );
}
if ( property_exists( $value, '@id' ) ) {
$triples[] = TypedRdfTriple::create( $this->getId(), $attribute, $value->$idProp, '@id' );
} else if ( property_exists( $value, '@value' ) ) {
$jsonLdValue = Value::fromJsonLd( $value );
$triple = TypedRdfTriple::create( $this->getId(), $attribute, $jsonLdValue->getValue() );
if ( $jsonLdValue instanceof TypedValue ) {
$triple->setObjectType( $jsonLdValue->getType() );
}
$triples[] = $triple;
}
}
// Check if we should serialize any child nodes
foreach ( $this->getMany( $attribute ) as $childNode ) {
if ( $childNode instanceof JsonLdNode ) {
// Serialize the child node if it is local, i.e. has a local URI or is anonymous
if ( $childNode->isBlankNode() || Util::isLocalUri( $childNode->getId() ) ) {
$triples = array_merge( $triples, $childNode->toRdfTriples() );
}
} }
} }
} }

View File

@ -4,8 +4,8 @@ namespace ActivityPub\JsonLd\TripleStore;
/** /**
* A triple represents a single fact in an RDF graph. A triple is made up a subject, a predicate, and an object. * A triple represents a single fact in an RDF graph. A triple is made up a subject, a predicate, and an object.
* The object can also have a type, e.g. @id for references to other resources or * The object can also have a type, e.g. "@id" for references to other resources or
* http://www.w3.org/2001/XMLSchema#dateTime for date-time values. * "http://www.w3.org/2001/XMLSchema#dateTime" for date-time values.
* *
* See https://www.w3.org/TR/rdf11-concepts/#data-model. * See https://www.w3.org/TR/rdf11-concepts/#data-model.
* *

View File

@ -11,6 +11,7 @@ use ActivityPub\Test\TestConfig\APTestCase;
use ActivityPub\Test\TestUtils\TestUuidProvider; use ActivityPub\Test\TestUtils\TestUuidProvider;
use ActivityPub\Utils\Logger; use ActivityPub\Utils\Logger;
use stdClass; use stdClass;
use Symfony\Component\HttpFoundation\Request;
class JsonLdNodeTest extends APTestCase class JsonLdNodeTest extends APTestCase
{ {
@ -509,9 +510,8 @@ class JsonLdNodeTest extends APTestCase
array( array(
TypedRdfTriple::create( TypedRdfTriple::create(
'https://example.org/collections/1', 'https://example.org/collections/1',
'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', '@id',
'https://www.w3.org/ns/activitystreams#Collection', 'https://example.org/collections/1'
'@id'
), ),
TypedRdfTriple::create( TypedRdfTriple::create(
'https://example.org/collections/1', 'https://example.org/collections/1',
@ -525,6 +525,26 @@ class JsonLdNodeTest extends APTestCase
'https://example.org/collections/1/items/2', 'https://example.org/collections/1/items/2',
'@id' '@id'
), ),
TypedRdfTriple::create(
'https://example.org/collections/1/items/1',
'@id',
'https://example.org/collections/1/items/1'
),
TypedRdfTriple::create(
'https://example.org/collections/1/items/1',
'@type',
'https://www.w3.org/ns/activitystreams#Note',
),
TypedRdfTriple::create(
'https://example.org/collections/1/items/2',
'@id',
'https://example.org/collections/1/items/2'
),
TypedRdfTriple::create(
'https://example.org/collections/1/items/2',
'@type',
'https://www.w3.org/ns/activitystreams#Note',
),
TypedRdfTriple::create( TypedRdfTriple::create(
'https://example.org/collections/1', 'https://example.org/collections/1',
'https://www.w3.org/ns/activitystreams#name', 'https://www.w3.org/ns/activitystreams#name',
@ -538,16 +558,9 @@ class JsonLdNodeTest extends APTestCase
'http://www.w3.org/2001/XMLSchema#dateTime' 'http://www.w3.org/2001/XMLSchema#dateTime'
), ),
TypedRdfTriple::create( TypedRdfTriple::create(
'https://example.org/collections/1/items/1', 'https://example.org/collections/1',
'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', '@type',
'https://www.w3.org/ns/activitystreams#Note', 'https://www.w3.org/ns/activitystreams#Collection',
'@id'
),
TypedRdfTriple::create(
'https://example.org/collections/1/items/2',
'http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
'https://www.w3.org/ns/activitystreams#Note',
'@id'
), ),
), ),
array( array(
@ -575,25 +588,29 @@ class JsonLdNodeTest extends APTestCase
'publicKeyPem' => 'the_public_key', 'publicKeyPem' => 'the_public_key',
) )
), ),
$this->asContext, array( 'https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1' ),
array( array(
TypedRdfTriple::create( TypedRdfTriple::create(
'https://example.org/sally', 'https://example.org/sally',
'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', '@id',
'https://www.w3.org/ns/activitystreams#Actor', 'https://example.org/sally'
'@id' ),
TypedRdfTriple::create(
$this->uuids[0],
'https://w3id.org/security#publicKeyPem',
'the_public_key',
'http://www.w3.org/2001/XMLSchema#string'
),
TypedRdfTriple::create(
'https://example.org/sally',
'@type',
'https://www.w3.org/ns/activitystreams#Actor'
), ),
TypedRdfTriple::create( TypedRdfTriple::create(
'https://example.org/sally', 'https://example.org/sally',
'https://w3id.org/security/v1#publicKey', 'https://w3id.org/security/v1#publicKey',
$this->uuids[0] $this->uuids[0]
), ),
TypedRdfTriple::create(
$this->uuids[0],
'https://w3id.org/security/v1#publicKeyPem',
'the_public_key',
'@id'
),
), ),
), ),
); );
@ -604,6 +621,8 @@ class JsonLdNodeTest extends APTestCase
*/ */
public function testToRdfTriple( $inputObj, $context, $expectedTriples, $nodeGraph = array() ) public function testToRdfTriple( $inputObj, $context, $expectedTriples, $nodeGraph = array() )
{ {
$r = Request::create( 'https://example.org' );
$r->overrideGlobals();
$node = $this->makeJsonLdNode( $inputObj, $context, $nodeGraph ); $node = $this->makeJsonLdNode( $inputObj, $context, $nodeGraph );
$triples = $node->toRdfTriples(); $triples = $node->toRdfTriples();
$this->assertEquals( $expectedTriples, $triples ); $this->assertEquals( $expectedTriples, $triples );
@ -616,4 +635,4 @@ class JsonLdNodeTest extends APTestCase
); );
return $factory->newNode( $inputObj ); return $factory->newNode( $inputObj );
} }
} }