6 Commits
12 changed files with 292 additions and 30 deletions
@@ -40,7 +40,7 @@ class AccountContext {
/** /**
* Create a new context using an AAUID and an OAuth 2.0 bearer access token. * Create a new context using an AAUID and an OAuth 2.0 bearer access token.
*/ */
public function __construct(IRI $aauid, $accessToken, DataLoader $dataLoader = null) { public function __construct(IRI $aauid, $accessToken, ?DataLoader $dataLoader = null) {
if (AAUIDParser::getType($aauid) != AAUIDParser::AAUID_ACCOUNT) if (AAUIDParser::getType($aauid) != AAUIDParser::AAUID_ACCOUNT)
throw new \Exception("Not a valid AAUID"); throw new \Exception("Not a valid AAUID");
+13 -6
View File
@@ -85,7 +85,7 @@ class CloudObject {
* Get the value of a property as a string. * Get the value of a property as a string.
* If the property has multiple values, only the first is returned. * If the property has multiple values, only the first is returned.
*/ */
public function getString($property, string $default = null) : ?string { public function getString($property, ?string $default = null) : ?string {
return $this->getReader()->getFirstValueString($this->node, $property, $default); return $this->getReader()->getFirstValueString($this->node, $property, $default);
} }
@@ -93,7 +93,7 @@ class CloudObject {
* Get the value of a property as an integer. * Get the value of a property as an integer.
* If the property has multiple values, only the first is returned. * If the property has multiple values, only the first is returned.
*/ */
public function getInt($property, int $default = null) : ?int { public function getInt($property, ?int $default = null) : ?int {
return $this->getReader()->getFirstValueInt($this->node, $property, $default); return $this->getReader()->getFirstValueInt($this->node, $property, $default);
} }
@@ -101,7 +101,7 @@ class CloudObject {
* Get the value of a property as a float. * Get the value of a property as a float.
* If the property has multiple values, only the first is returned. * If the property has multiple values, only the first is returned.
*/ */
public function getFloat($property, float $default = null) : ?float { public function getFloat($property, ?float $default = null) : ?float {
return $this->getReader()->getFirstValueFloat($this->node, $property, $default); return $this->getReader()->getFirstValueFloat($this->node, $property, $default);
} }
@@ -109,7 +109,7 @@ class CloudObject {
* Get the value of a property as a boolean. * Get the value of a property as a boolean.
* If the property has multiple values, only the first is returned. * If the property has multiple values, only the first is returned.
*/ */
public function getBool($property, bool $default = null) : ?bool { public function getBool($property, ?bool $default = null) : ?bool {
return $this->getReader()->getFirstValueBool($this->node, $property, $default); return $this->getReader()->getFirstValueBool($this->node, $property, $default);
} }
@@ -117,7 +117,7 @@ class CloudObject {
* Get the value of a property as an IRI. * Get the value of a property as an IRI.
* If the property has multiple values, only the first is returned. * If the property has multiple values, only the first is returned.
*/ */
public function getIRI($property, IRI $default = null) : ?IRI { public function getIRI($property, ?IRI $default = null) : ?IRI {
return $this->getReader()->getFirstValueIRI($this->node, $property, $default); return $this->getReader()->getFirstValueIRI($this->node, $property, $default);
} }
@@ -125,7 +125,7 @@ class CloudObject {
* Get the value of a property as a Node. * Get the value of a property as a Node.
* If the property has multiple values, only the first is returned. * If the property has multiple values, only the first is returned.
*/ */
public function getNode($property, Node $default = null) : ?Node { public function getNode($property, ?Node $default = null) : ?Node {
return $this->getReader()->getFirstValueNode($this->node, $property, $default); return $this->getReader()->getFirstValueNode($this->node, $property, $default);
} }
@@ -166,4 +166,11 @@ class CloudObject {
return $this->getString(Constants::PROPERTY_REVISION); return $this->getString(Constants::PROPERTY_REVISION);
} }
/**
* Get the label of the object.
*/
public function getLabel() : ?string {
return $this->getString(Constants::RDFS_LABEL);
}
} }
+1 -1
View File
@@ -53,7 +53,7 @@ class CryptoHelper {
* @param ObjectRetriever $objectRetriever An initialized and authenticated object retriever. * @param ObjectRetriever $objectRetriever An initialized and authenticated object retriever.
* @param IRI|null $namespaceCoid The namespace used to retrieve keys. If this parameter is not provided, the namespace provided with the "auth_ns" configuration option from the object retriever is used. * @param IRI|null $namespaceCoid The namespace used to retrieve keys. If this parameter is not provided, the namespace provided with the "auth_ns" configuration option from the object retriever is used.
*/ */
public function __construct(ObjectRetriever $objectRetriever, IRI $namespaceCoid = null) { public function __construct(ObjectRetriever $objectRetriever, ?IRI $namespaceCoid = null) {
if (!class_exists('Defuse\Crypto\Crypto')) if (!class_exists('Defuse\Crypto\Crypto'))
throw new Exception("Run composer require defuse/php-encryption before using CryptoHelper."); throw new Exception("Run composer require defuse/php-encryption before using CryptoHelper.");
+1
View File
@@ -9,5 +9,6 @@ namespace CloudObjects\SDK;
class Constants { class Constants {
const PROPERTY_REVISION = 'coid://cloudobjects.io/isAtRevision'; const PROPERTY_REVISION = 'coid://cloudobjects.io/isAtRevision';
const RDFS_LABEL = 'http://www.w3.org/2000/01/rdf-schema#label';
} }
+18 -18
View File
@@ -38,7 +38,7 @@ class NodeReader {
* @param string|object $type The type to check for. * @param string|object $type The type to check for.
* @return boolean * @return boolean
*/ */
public function hasType(Node $node = null, $type) { public function hasType(?Node $node = null, $type) {
if (!isset($node)) if (!isset($node))
return false; return false;
$type = $this->expand($type); $type = $this->expand($type);
@@ -60,7 +60,7 @@ class NodeReader {
return false; return false;
} }
private function getFirstValue(Node $node = null, $property, $default = null) { private function getFirstValue(?Node $node = null, $property, $default = null) {
if (!isset($node)) if (!isset($node))
return $default; return $default;
$valueFromNode = $node->getProperty($this->expand($property)); $valueFromNode = $node->getProperty($this->expand($property));
@@ -82,7 +82,7 @@ class NodeReader {
* @param $default The default that is returned if no value for the property exists on the node. * @param $default The default that is returned if no value for the property exists on the node.
* @return string|null * @return string|null
*/ */
public function getFirstValueString(Node $node = null, $property, $default = null) { public function getFirstValueString(?Node $node = null, $property, $default = null) {
$valueFromNode = $this->getFirstValue($node, $property, $default); $valueFromNode = $this->getFirstValue($node, $property, $default);
if ($valueFromNode == $default) if ($valueFromNode == $default)
return $default; return $default;
@@ -103,7 +103,7 @@ class NodeReader {
* @param $default The default that is returned if no value for the property exists on the node. * @param $default The default that is returned if no value for the property exists on the node.
* @return bool|null * @return bool|null
*/ */
public function getFirstValueBool(Node $node = null, $property, $default = null) { public function getFirstValueBool(?Node $node = null, $property, $default = null) {
return (in_array( return (in_array(
$this->getFirstValueString($node, $property, $default), $this->getFirstValueString($node, $property, $default),
[ '1', 'true' ] [ '1', 'true' ]
@@ -120,7 +120,7 @@ class NodeReader {
* @param $default The default that is returned if no value for the property exists on the node. * @param $default The default that is returned if no value for the property exists on the node.
* @return int|null * @return int|null
*/ */
public function getFirstValueInt(Node $node = null, $property, $default = null) { public function getFirstValueInt(?Node $node = null, $property, $default = null) {
$value = $this->getFirstValueString($node, $property); $value = $this->getFirstValueString($node, $property);
if (is_numeric($value)) if (is_numeric($value))
return (int)($value); return (int)($value);
@@ -138,7 +138,7 @@ class NodeReader {
* @param $default The default that is returned if no value for the property exists on the node. * @param $default The default that is returned if no value for the property exists on the node.
* @return float|null * @return float|null
*/ */
public function getFirstValueFloat(Node $node = null, $property, $default = null) { public function getFirstValueFloat(?Node $node = null, $property, $default = null) {
$value = $this->getFirstValueString($node, $property); $value = $this->getFirstValueString($node, $property);
if (is_numeric($value)) if (is_numeric($value))
return (float)($value); return (float)($value);
@@ -156,7 +156,7 @@ class NodeReader {
* @param $default The default that is returned if no value for the property exists on the node. * @param $default The default that is returned if no value for the property exists on the node.
* @return string|null * @return string|null
*/ */
public function getFirstValueIRI(Node $node = null, $property, IRI $default = null) { public function getFirstValueIRI(?Node $node = null, $property, ?IRI $default = null) {
$valueFromNode = $this->getFirstValue($node, $property, $default); $valueFromNode = $this->getFirstValue($node, $property, $default);
if ($valueFromNode == $default) if ($valueFromNode == $default)
return $default; return $default;
@@ -177,7 +177,7 @@ class NodeReader {
* @param $default The default that is returned if no value for the property exists on the node. * @param $default The default that is returned if no value for the property exists on the node.
* @return string|null * @return string|null
*/ */
public function getFirstValueNode(Node $node = null, $property, Node $default = null) { public function getFirstValueNode(?Node $node = null, $property, ?Node $default = null) {
$valueFromNode = $this->getFirstValue($node, $property, $default); $valueFromNode = $this->getFirstValue($node, $property, $default);
if ($valueFromNode == $default) if ($valueFromNode == $default)
return $default; return $default;
@@ -196,7 +196,7 @@ class NodeReader {
* @param string|object $value The expected value. * @param string|object $value The expected value.
* @return boolean * @return boolean
*/ */
public function hasPropertyValue(Node $node = null, $property, $value) { public function hasPropertyValue(?Node $node = null, $property, $value) {
if (!isset($node)) if (!isset($node))
return false; return false;
$valuesFromNode = $node->getProperty($this->expand($property)); $valuesFromNode = $node->getProperty($this->expand($property));
@@ -225,14 +225,14 @@ class NodeReader {
* @param string|object $property The property to read. * @param string|object $property The property to read.
* @return boolean * @return boolean
*/ */
public function hasProperty(Node $node = null, $property) { public function hasProperty(?Node $node = null, $property) {
if (!isset($node)) if (!isset($node))
return false; return false;
return ($node->getProperty($this->expand($property)) != null); return ($node->getProperty($this->expand($property)) != null);
} }
private function getAllValues(Node $node = null, $property) { private function getAllValues(?Node $node = null, $property) {
if (!isset($node)) if (!isset($node))
return []; return [];
@@ -248,7 +248,7 @@ class NodeReader {
* Get the language-tagged-string for the property in the specified language. * Get the language-tagged-string for the property in the specified language.
* If no value is found for the specified language, the default is returned. * If no value is found for the specified language, the default is returned.
*/ */
public function getLocalizedString(Node $node = null, $property, $language, $default = null) { public function getLocalizedString(?Node $node = null, $property, $language, $default = null) {
$values = $this->getAllValues($node, $property); $values = $this->getAllValues($node, $property);
foreach ($values as $v) { foreach ($values as $v) {
if (is_a($v, 'ML\JsonLD\LanguageTaggedString') && $v->getLanguage() == $language) if (is_a($v, 'ML\JsonLD\LanguageTaggedString') && $v->getLanguage() == $language)
@@ -265,7 +265,7 @@ class NodeReader {
* @param string|object $property The property to read. * @param string|object $property The property to read.
* @return array<string> * @return array<string>
*/ */
public function getAllValuesString(Node $node = null, $property) { public function getAllValuesString(?Node $node = null, $property) {
$allValues = $this->getAllValues($node, $property); $allValues = $this->getAllValues($node, $property);
$output = []; $output = [];
foreach ($allValues as $a) foreach ($allValues as $a)
@@ -284,7 +284,7 @@ class NodeReader {
* @param string|object $property The property to read. * @param string|object $property The property to read.
* @return array<bool> * @return array<bool>
*/ */
public function getAllValuesBool(Node $node = null, $property) { public function getAllValuesBool(?Node $node = null, $property) {
$allValues = $this->getAllValuesString($node, $property); $allValues = $this->getAllValuesString($node, $property);
$output = []; $output = [];
foreach ($allValues as $a) foreach ($allValues as $a)
@@ -300,7 +300,7 @@ class NodeReader {
* @param string|object $property The property to read. * @param string|object $property The property to read.
* @return array<bool> * @return array<bool>
*/ */
public function getAllValuesInt(Node $node = null, $property) { public function getAllValuesInt(?Node $node = null, $property) {
$allValues = $this->getAllValuesString($node, $property); $allValues = $this->getAllValuesString($node, $property);
$output = []; $output = [];
foreach ($allValues as $a) foreach ($allValues as $a)
@@ -316,7 +316,7 @@ class NodeReader {
* @param string|object $property The property to read. * @param string|object $property The property to read.
* @return array<bool> * @return array<bool>
*/ */
public function getAllValuesFloat(Node $node = null, $property) { public function getAllValuesFloat(?Node $node = null, $property) {
$allValues = $this->getAllValuesString($node, $property); $allValues = $this->getAllValuesString($node, $property);
$output = []; $output = [];
foreach ($allValues as $a) foreach ($allValues as $a)
@@ -333,7 +333,7 @@ class NodeReader {
* @param string|object $property The property to read. * @param string|object $property The property to read.
* @return array<IRI> * @return array<IRI>
*/ */
public function getAllValuesIRI(Node $node = null, $property) { public function getAllValuesIRI(?Node $node = null, $property) {
$allValues = $this->getAllValues($node, $property); $allValues = $this->getAllValues($node, $property);
$output = []; $output = [];
foreach ($allValues as $a) foreach ($allValues as $a)
@@ -351,7 +351,7 @@ class NodeReader {
* @param string|object $property The property to read. * @param string|object $property The property to read.
* @return array<Node> * @return array<Node>
*/ */
public function getAllValuesNode(Node $node = null, $property) { public function getAllValuesNode(?Node $node = null, $property) {
$allValues = $this->getAllValues($node, $property); $allValues = $this->getAllValues($node, $property);
$output = []; $output = [];
foreach ($allValues as $a) foreach ($allValues as $a)
@@ -0,0 +1,80 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\SDK;
use Exception;
use ML\IRI\IRI;
use ML\JsonLD\Node;
/**
* Static facade for ObjectRetriever. Call setObjectRetriever() once to
* initialize; all subsequent static calls are forwarded to that instance.
*/
class ObjectRetrieverFacade {
private static ?ObjectRetriever $instance = null;
public static function setObjectRetriever(ObjectRetriever $retriever) : void {
self::$instance = $retriever;
}
private static function getInstance() : ObjectRetriever {
if (self::$instance === null)
throw new Exception('ObjectRetrieverFacade has not been initialized. Call setObjectRetriever() first.');
return self::$instance;
}
public static function setDefaultReader(NodeReader $reader) : ObjectRetriever {
return self::getInstance()->setDefaultReader($reader);
}
public static function getDefaultReader() : NodeReader {
return self::getInstance()->getDefaultReader();
}
public static function getClient() {
return self::getInstance()->getClient();
}
public static function getCloudObject(IRI $coid) : ?CloudObject {
return self::getInstance()->getCloudObject($coid);
}
public static function getObjectNode(IRI $coid) : ?Node {
return self::getInstance()->getObjectNode($coid);
}
public static function fetchObjectsInNamespaceWithType(IRI $namespaceCoid, $type) : array {
return self::getInstance()->fetchObjectsInNamespaceWithType($namespaceCoid, $type);
}
public static function fetchAllObjectsInNamespace(IRI $namespaceCoid) : array {
return self::getInstance()->fetchAllObjectsInNamespace($namespaceCoid);
}
public static function getCOIDListForNamespace(IRI $namespaceCoid) : array {
return self::getInstance()->getCOIDListForNamespace($namespaceCoid);
}
public static function getCOIDListForNamespaceWithType(IRI $namespaceCoid, $type) : array {
return self::getInstance()->getCOIDListForNamespaceWithType($namespaceCoid, $type);
}
public static function getAttachment(IRI $coid, $filename) {
return self::getInstance()->getAttachment($coid, $filename);
}
public static function getAuthenticatingNamespaceObjectNode() : ?Node {
return self::getInstance()->getAuthenticatingNamespaceObjectNode();
}
public static function getAuthenticatingNamespaceCloudObject() : ?CloudObject {
return self::getInstance()->getAuthenticatingNamespaceCloudObject();
}
}
+1 -1
View File
@@ -217,7 +217,7 @@ class APIClientFactory {
* @param ObjectRetriever $objectRetriever An initialized and authenticated object retriever. * @param ObjectRetriever $objectRetriever An initialized and authenticated object retriever.
* @param IRI|null $namespaceCoid The namespace of the API client. Used to retrieve credentials. If this parameter is not provided, the namespace provided with the "auth_ns" configuration option from the object retriever is used. * @param IRI|null $namespaceCoid The namespace of the API client. Used to retrieve credentials. If this parameter is not provided, the namespace provided with the "auth_ns" configuration option from the object retriever is used.
*/ */
public function __construct(ObjectRetriever $objectRetriever, IRI $namespaceCoid = null) { public function __construct(ObjectRetriever $objectRetriever, ?IRI $namespaceCoid = null) {
$this->objectRetriever = $objectRetriever; $this->objectRetriever = $objectRetriever;
$this->namespace = isset($namespaceCoid) $this->namespace = isset($namespaceCoid)
? $objectRetriever->getObjectNode($namespaceCoid) ? $objectRetriever->getObjectNode($namespaceCoid)
+6 -3
View File
@@ -19,9 +19,12 @@
} }
], ],
"autoload": { "autoload": {
"psr-0": { "psr-4": {
"CloudObjects\\SDK" : "" "CloudObjects\\SDK\\" : "CloudObjects/SDK/"
} },
"files": [
"functions.php"
]
}, },
"require-dev" : { "require-dev" : {
"phpunit/phpunit": "^10", "phpunit/phpunit": "^10",
+23
View File
@@ -0,0 +1,23 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use ML\IRI\IRI;
use CloudObjects\SDK\CloudObject,
CloudObjects\SDK\ObjectRetrieverFacade;
if (!function_exists('cloudobjects_get_object')) {
/**
* Retrieve a CloudObject by COID. Accepts a COID as an IRI object or a string.
*/
function cloudobjects_get_object($coid) : ?CloudObject {
if (is_string($coid))
$coid = new IRI($coid);
elseif (!($coid instanceof IRI))
throw new InvalidArgumentException('COID must be a string or an IRI object.');
return ObjectRetrieverFacade::getCloudObject($coid);
}
}
+63
View File
@@ -0,0 +1,63 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\SDK;
use ML\IRI\IRI;
use ReflectionProperty,
InvalidArgumentException;
class FunctionsTest extends \PHPUnit\Framework\TestCase {
protected function setUp(): void {
$prop = new ReflectionProperty(ObjectRetrieverFacade::class, 'instance');
$prop->setAccessible(true);
$prop->setValue(null, null);
}
private function makeMockRetrieverReturning(?CloudObject $object) : ObjectRetriever {
$mock = $this->createMock(ObjectRetriever::class);
$mock->method('getCloudObject')->willReturn($object);
return $mock;
}
public function testAcceptsIRI(): void {
$coid = new IRI('coid://cloudobjects.io');
$mockObject = $this->createMock(CloudObject::class);
$mockRetriever = $this->createMock(ObjectRetriever::class);
$mockRetriever->expects($this->once())
->method('getCloudObject')
->with($coid)
->willReturn($mockObject);
ObjectRetrieverFacade::setObjectRetriever($mockRetriever);
$this->assertSame($mockObject, cloudobjects_get_object($coid));
}
public function testConvertsStringToIRI(): void {
$mockObject = $this->createMock(CloudObject::class);
$mockRetriever = $this->createMock(ObjectRetriever::class);
$mockRetriever->expects($this->once())
->method('getCloudObject')
->with($this->callback(fn($arg) => $arg instanceof IRI && (string)$arg === 'coid://cloudobjects.io'))
->willReturn($mockObject);
ObjectRetrieverFacade::setObjectRetriever($mockRetriever);
$this->assertSame($mockObject, cloudobjects_get_object('coid://cloudobjects.io'));
}
public function testThrowsOnInvalidArgumentType(): void {
ObjectRetrieverFacade::setObjectRetriever($this->makeMockRetrieverReturning(null));
$this->expectException(InvalidArgumentException::class);
cloudobjects_get_object(42);
}
}
@@ -126,6 +126,15 @@ class NodeReaderMockTest extends \PHPUnit\Framework\TestCase {
$this->assertEquals('coid://cloudobjects.io/Public', $object->getNode('co:isVisibleTo')->getId()); $this->assertEquals('coid://cloudobjects.io/Public', $object->getNode('co:isVisibleTo')->getId());
} }
public function testConstants() {
$coid = new IRI('coid://cloudobjects.io');
$this->useRootResourceMock();
$object = $this->retriever->getCloudObject($coid);
$this->assertEquals('6-fbea0c90b2c5e5300e4039ed99be9b2d', $object->getRevision());
$this->assertEquals('CloudObjects', $object->getLabel());
}
public function testGetAllValuesString1() { public function testGetAllValuesString1() {
$coid = new IRI('coid://cloudobjects.io'); $coid = new IRI('coid://cloudobjects.io');
$this->useRootResourceMock(); $this->useRootResourceMock();
@@ -0,0 +1,76 @@
<?php
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace CloudObjects\SDK;
use Exception;
use ML\IRI\IRI;
use ML\JsonLD\Node;
use ReflectionProperty;
class ObjectRetrieverFacadeTest extends \PHPUnit\Framework\TestCase {
protected function setUp(): void {
$prop = new ReflectionProperty(ObjectRetrieverFacade::class, 'instance');
$prop->setAccessible(true);
$prop->setValue(null, null);
}
public function testThrowsExceptionBeforeInitialization(): void {
$this->expectException(Exception::class);
ObjectRetrieverFacade::getObjectNode(new IRI('coid://cloudobjects.io'));
}
public function testForwardsGetObjectNodeToInstance(): void {
$coid = new IRI('coid://cloudobjects.io');
$mockNode = $this->createMock(Node::class);
$mockRetriever = $this->createMock(ObjectRetriever::class);
$mockRetriever->expects($this->once())
->method('getObjectNode')
->with($coid)
->willReturn($mockNode);
ObjectRetrieverFacade::setObjectRetriever($mockRetriever);
$this->assertSame($mockNode, ObjectRetrieverFacade::getObjectNode($coid));
}
public function testForwardsGetCloudObjectToInstance(): void {
$coid = new IRI('coid://cloudobjects.io');
$mockCloudObject = $this->createMock(CloudObject::class);
$mockRetriever = $this->createMock(ObjectRetriever::class);
$mockRetriever->expects($this->once())
->method('getCloudObject')
->with($coid)
->willReturn($mockCloudObject);
ObjectRetrieverFacade::setObjectRetriever($mockRetriever);
$this->assertSame($mockCloudObject, ObjectRetrieverFacade::getCloudObject($coid));
}
public function testReplacingRetrieverUsesNewInstance(): void {
$coid = new IRI('coid://cloudobjects.io');
$mockNode = $this->createMock(Node::class);
$firstRetriever = $this->createMock(ObjectRetriever::class);
$firstRetriever->expects($this->never())->method('getObjectNode');
$secondRetriever = $this->createMock(ObjectRetriever::class);
$secondRetriever->expects($this->once())
->method('getObjectNode')
->with($coid)
->willReturn($mockNode);
ObjectRetrieverFacade::setObjectRetriever($firstRetriever);
ObjectRetrieverFacade::setObjectRetriever($secondRetriever);
$this->assertSame($mockNode, ObjectRetrieverFacade::getObjectNode($coid));
}
}