Skip to content

Commit

Permalink
Add RpdeBody::deserialize() functionality
Browse files Browse the repository at this point in the history
Fixes #59
  • Loading branch information
Nathan Salter committed Oct 12, 2020
1 parent f8b8a0c commit 91363fc
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 34 deletions.
10 changes: 8 additions & 2 deletions src/Concerns/TypeChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,18 @@ private static function getTypeCheckerErrorLocation()
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
$location = [];
$ns = 'OpenActive\\Models\\OA\\';
$rpdeNs = 'OpenActive\\Rpde\\';
foreach ($trace as $call) {
if (0 !== strpos($call['class'], $ns)) {
$loc = isset($call['class']) ? $call['class'] : '';
if (0 === strpos($loc, $rpdeNs) && !in_array($loc, $location)) {
$location[] = str_replace($ns, '', $loc);
continue;
}
if (0 !== strpos($loc, $ns)) {
continue;
}
$location[] = preg_replace('/set([A-Z])/', '$1', $call['function']);
$location[] = str_replace($ns, '', $call['class']);
$location[] = str_replace($ns, '', $loc);
}

return implode('.', array_reverse($location));
Expand Down
26 changes: 18 additions & 8 deletions src/Rpde/RpdeBody.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,7 @@ class RpdeBody implements SerializerInterface, TypeCheckerInterface
private function __construct($data)
{
foreach ($data as $key => $value) {
// Make sure setter is cased properly
$methodName = "set" . Str::pascal($key);

if (method_exists($this, $methodName) === true) {
$this->$methodName($value);
}
$this->defineProperty($key, $value);
}
}

Expand Down Expand Up @@ -300,9 +295,9 @@ public function getItems()
*/
public function setItems($items)
{
$types = array(
$types = [
"\OpenActive\Rpde\RpdeItem[]",
);
];

$items = self::checkTypes($items, $types);

Expand Down Expand Up @@ -331,4 +326,19 @@ public function setLicense($license)

$this->license = $license;
}

public function defineProperty($key, $value)
{
// Ignore properties which start with @
if ('@' === $key{0}) {
return;
}

// Make sure setter is cased properly
$methodName = "set" . Str::pascal($key);

if (method_exists($this, $methodName) === true) {
$this->$methodName($value);
}
}
}
1 change: 1 addition & 0 deletions src/Rpde/RpdeItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ public function setData($data)
{
$types = array(
"\OpenActive\BaseModel",
"\\OpenActive\\Rpde\\RpdeItemData",
"null",
);

Expand Down
29 changes: 5 additions & 24 deletions src/Validators/ArrayOfValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,11 @@ public function __construct($itemValidator)
*/
public function coerce($value)
{
// NOTE: OpenActive is more strict than schema.org in this regard, so commenting out this for now
// $nullValidator = new NullValidator();

// If we are providing a single item of the itemValidator type (or null)
// Put the value inside an array
// if(
// $nullValidator->run($value) === true ||
// $this->itemValidator->run($value) === true
// ) {
// return [$value];
// }

// Otherwise this is a no-op
return $value;
$newValue = [];
foreach ($value as $key => $item) {
$newValue[$key] = $this->itemValidator->coerce($item);
}
return $newValue;
}

/**
Expand All @@ -52,16 +43,6 @@ public function run($value)
{
$nullValidator = new NullValidator();

// NOTE: OpenActive is more strict than schema.org in this regard, so commenting out this for now
// If we are providing a single item of the itemValidator type (or null)
// Validation passes (but the value will need to be coerced to array)
// if(
// $nullValidator->run($value) === true ||
// $this->itemValidator->run($value) === true
// ) {
// return true;
// }

// Check if value is an array
if ((new ArrayValidator())->run($value) === false) {
return false;
Expand Down
7 changes: 7 additions & 0 deletions src/Validators/BaseValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ public static function getValidator($type)
return new RpdeEnumValidator($type);
}

if ($type === "\\OpenActive\\Rpde\\RpdeItem") {
return new RpdeItemValidator();
}
if ($type === "\\OpenActive\\Rpde\\RpdeItemData") {
return new RpdeItemDataValidator();
}

// If type is an OpenActive BaseModel class
if ($type === "\\OpenActive\\BaseModel") {
return new BaseModelValidator();
Expand Down
53 changes: 53 additions & 0 deletions src/Validators/RpdeItemDataValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace OpenActive\Validators;

use OpenActive\BaseModel;

class RpdeItemDataValidator implements ValidatorInterface
{
public function run($value)
{
if ($value instanceof BaseModel) {
return true;
}
if (null === $value) {
return true;
}
if (is_object($value)) {
$value = (array) $value;
}
return isset($value['@type'])
&& null !== $this->getValidClass($value['@type']);
}

public function coerce($value)
{
if ($value instanceof BaseModel) {
return $value;
}
if (null === $value) {
return $value;
}

$class = $this->getValidClass($value['@type']);
if (null === $class) {
throw new \InvalidArgumentException(sprintf('Invalid type %s given, no instantiable class', $value['@type']));
}
return new $class($value);
}

private function getValidClass($type)
{
$classOa = sprintf('\\OpenActive\\Models\\OA\\%s', $type);
$classSchema = sprintf('\\OpenActive\\Models\\SchemaOrg\\%s', $type);

if (class_exists($classOa)) {
return $classOa;
}
if (class_exists($classSchema)) {
return $classSchema;
}
return null;
}
}
39 changes: 39 additions & 0 deletions src/Validators/RpdeItemValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace OpenActive\Validators;

use OpenActive\Concerns\TypeChecker;
use OpenActive\Rpde\RpdeItem;

class RpdeItemValidator implements ValidatorInterface
{
use TypeChecker;

public function run($value)
{
if ($value instanceof RpdeItem) {
return true;
}
if (is_object($value)) {
$value = (array) $value;
}

if (!isset($value['state'], $value['kind'], $value['id'], $value['modified'])) {
return false;
}

if ('deleted' === $value['state']) {
return true;
}

return isset($value['data']);
}

public function coerce($value)
{
if ($value instanceof RpdeItem) {
return $value;
}
return new RpdeItem($value);
}
}
19 changes: 19 additions & 0 deletions tests/Unit/RpdeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,25 @@ public function testCreatesSerializedRpdeFeedPageWithAllTypes($feed, $expectedJs
json_decode(RpdeBody::serialize($body))
);
}
/**
* @dataProvider allTypesDataProvider
* @param array $feed
* @param string $expectedJson
*/
public function testAbleToUnserializeRpdeFeed($feed, $expectedJson)
{
$body = RpdeBody::createFromModifiedId(
'https://www.example.com/feed',
1,
"1",
$feed
);

$this->assertEquals(
$body,
RpdeBody::deserialize(RpdeBody::serialize($body))
);
}

/**
* Test the serialized RPDE body created with createFromModifiedId returns the expected JSON-LD.
Expand Down

0 comments on commit 91363fc

Please sign in to comment.