diff --git a/src/Concerns/TypeChecker.php b/src/Concerns/TypeChecker.php index 24cb5ec0..9bf3d87b 100644 --- a/src/Concerns/TypeChecker.php +++ b/src/Concerns/TypeChecker.php @@ -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)); diff --git a/src/Rpde/RpdeBody.php b/src/Rpde/RpdeBody.php index df2875e3..b377e4cd 100644 --- a/src/Rpde/RpdeBody.php +++ b/src/Rpde/RpdeBody.php @@ -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); } } @@ -300,9 +295,9 @@ public function getItems() */ public function setItems($items) { - $types = array( + $types = [ "\OpenActive\Rpde\RpdeItem[]", - ); + ]; $items = self::checkTypes($items, $types); @@ -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); + } + } } diff --git a/src/Rpde/RpdeItem.php b/src/Rpde/RpdeItem.php index 565c704e..63e18643 100644 --- a/src/Rpde/RpdeItem.php +++ b/src/Rpde/RpdeItem.php @@ -176,6 +176,7 @@ public function setData($data) { $types = array( "\OpenActive\BaseModel", + "\\OpenActive\\Rpde\\RpdeItemData", "null", ); diff --git a/src/Validators/ArrayOfValidator.php b/src/Validators/ArrayOfValidator.php index 6ec4ce69..212081df 100644 --- a/src/Validators/ArrayOfValidator.php +++ b/src/Validators/ArrayOfValidator.php @@ -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; } /** @@ -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; diff --git a/src/Validators/BaseValidator.php b/src/Validators/BaseValidator.php index 1afccff8..6ab69e47 100644 --- a/src/Validators/BaseValidator.php +++ b/src/Validators/BaseValidator.php @@ -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(); diff --git a/src/Validators/RpdeItemDataValidator.php b/src/Validators/RpdeItemDataValidator.php new file mode 100644 index 00000000..3f8f0180 --- /dev/null +++ b/src/Validators/RpdeItemDataValidator.php @@ -0,0 +1,53 @@ +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; + } +} diff --git a/src/Validators/RpdeItemValidator.php b/src/Validators/RpdeItemValidator.php new file mode 100644 index 00000000..f945a8b8 --- /dev/null +++ b/src/Validators/RpdeItemValidator.php @@ -0,0 +1,39 @@ +assertEquals( + $body, + RpdeBody::deserialize(RpdeBody::serialize($body)) + ); + } /** * Test the serialized RPDE body created with createFromModifiedId returns the expected JSON-LD.