clean install

This commit is contained in:
2024-12-10 15:08:16 +01:00
commit e14eb2d8fd
31193 changed files with 3555714 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
<?php
namespace Shaper\DataAdaptor;
use Shaper\Transformation\TransformationInterface;
/**
* Transformation pair that can act as an adaptor between systems.
*
* Makes sure that data leaving A transforms into format B, and data arriving
* from B complies with the format requirements of A.
*
* @package Shaper
*/
abstract class DataAdaptorBase implements TransformationInterface, ReversibleTransformationInterface, ReversibleTransformationValidationInterface {
use DataAdaptorValidatorTrait;
use DataAdaptorTransformerTrait;
}

View File

@@ -0,0 +1,107 @@
<?php
namespace Shaper\DataAdaptor;
use Shaper\Util\Context;
trait DataAdaptorTransformerTrait {
/**
* {@inheritdoc}
*/
public function transform($data, ?Context $context = NULL) {
if (!isset($context)) {
$context = new Context();
}
if (!$this->conformsToExpectedInputShape($data, $context)) {
/** @var \Shaper\Validator\ValidateableInterface $validator */
$validator = $this->getInputValidator();
$message = sprintf(
'Adaptor %s received invalid input data: %s',
__CLASS__,
json_encode($validator->getErrors(), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT)
);
throw new \TypeError($message);
}
$output = $this->doTransform($data, $context);
if (!$this->conformsToInternalShape($output, $context)) {
/** @var \Shaper\Validator\ValidateableInterface $validator */
$validator = $this->getInternalValidator();
$message = sprintf(
'Adaptor %s returned invalid output data: %s',
__CLASS__,
json_encode($validator->getErrors(), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT)
);
throw new \TypeError($message);
}
return $output;
}
/**
* {@inheritdoc}
*/
public function undoTransform($data, ?Context $context = NULL) {
if (!isset($context)) {
$context = new Context();
}
if (!$this->conformsToInternalShape($data, $context)) {
/** @var \Shaper\Validator\ValidateableInterface $validator */
$validator = $this->getInternalValidator();
$message = sprintf(
'Adaptor %s received invalid input data: %s',
__CLASS__,
json_encode($validator->getErrors(), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT)
);
throw new \TypeError($message);
}
$output = $this->doUndoTransform($data, $context);
if (!$this->conformsToOutputShape($output, $context)) {
/** @var \Shaper\Validator\ValidateableInterface $validator */
$validator = $this->getOutputValidator();
$message = sprintf(
'Adaptor %s returned invalid output data: %s',
__CLASS__,
json_encode($validator->getErrors(), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT)
);
throw new \TypeError($message);
}
return $output;
}
/**
* Transforms incoming data into another shape.
*
* This method will validate data coming in and going out using validators.
*
* @param mixed $data
* The data to transform.
* @param \Shaper\Util\Context $context
* Additional information that will affect how the data is transformed.
*
* @return mixed
* The data in the new shape.
*
* @throws \TypeError
* When the transformation cannot be applied.
*/
abstract protected function doTransform($data, Context $context);
/**
* Transforms outgoing data into another shape.
*
* This method will validate data coming in and going out using validators.
*
* @param mixed $data
* The data to transform.
* @param \Shaper\Util\Context $context
* Additional information that will affect how the data is transformed.
*
* @return mixed
* The data in the new shape.
*
* @throws \TypeError
* When the transformation cannot be applied.
*/
abstract protected function doUndoTransform($data, Context $context);
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Shaper\DataAdaptor;
use Shaper\Transformation\TransformationValidationTrait;
use Shaper\Util\Context;
trait DataAdaptorValidatorTrait {
use TransformationValidationTrait;
/**
* {@inheritdoc}
*/
public function conformsToInternalShape($data, ?Context $context = NULL) {
return $this->getInternalValidator()->isValid($data);
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Shaper\DataAdaptor;
use Shaper\Util\Context;
interface ReversibleTransformationInterface {
/**
* Basic transformation revert from a shape into another shape.
*
* This method will validate data coming in and going out using validators.
*
* @param mixed $data
* The data to transform.
*
* @param \Shaper\Util\Context $context
* Additional information that will affect how the data is transformed.
*
* @return mixed
* The data in the new shape.
*
* @throws \TypeError
* When the transformation cannot be applied.
*/
public function undoTransform($data, ?Context $context = NULL);
}

View File

@@ -0,0 +1,30 @@
<?php
namespace Shaper\DataAdaptor;
use Shaper\Transformation\TransformationValidationInterface;
use Shaper\Util\Context;
interface ReversibleTransformationValidationInterface extends TransformationValidationInterface {
/**
* Checks if the shape of the transformed data is valid for internal use.
*
* @param mixed $data
* The data in the internal format.
* @param \Shaper\Util\Context $context
* Additional information that will affect how the data is transformed.
*
* @return bool
* TRUE if the format is valid.
*/
public function conformsToInternalShape($data, ?Context $context = NULL);
/**
* The validator for the internal data.
*
* @return \Shaper\Validator\ValidateableInterface
*/
public function getInternalValidator();
}

View File

@@ -0,0 +1,15 @@
<?php
namespace Shaper\Transformation;
/**
* Base implementation for transformation classes.
*
* @package Shaper
*/
abstract class TransformationBase implements TransformationInterface, TransformationValidationInterface {
use TransformationValidationTrait;
use TransformationTransformerTrait;
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Shaper\Transformation;
use Shaper\Util\Context;
/**
* Interface for transformation classes.
*
* @package Shaper
*/
interface TransformationInterface {
/**
* Basic transformation from a shape into another shape.
*
* This method will validate data coming in and going out using validators.
*
* @param mixed $data
* The data to transform.
*
* @param \Shaper\Util\Context $context
* Additional information that will affect how the data is transformed.
*
* @return mixed
* The data in the new shape.
*
* @throws \TypeError
* When the transformation cannot be applied.
*/
public function transform($data, ?Context $context = NULL);
}

View File

@@ -0,0 +1,60 @@
<?php
namespace Shaper\Transformation;
use Shaper\Util\Context;
trait TransformationTransformerTrait {
/**
* {@inheritdoc}
*/
public function transform($data, ?Context $context = NULL) {
if (!isset($context)) {
$context = new Context();
}
// Error utility.
$throw = function($message, $arguments = []) {
/** @var \Shaper\Validator\ValidateableInterface $validator */
$validator = $this->getInputValidator();
$options = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT;
throw new \TypeError(strtr($message, $arguments + [
'{class}' => static::class,
'{data}' => json_encode($validator->getErrors(), $options)
]));
};
if (!$this->conformsToExpectedInputShape($data, $context)) {
$throw('Adaptor {class} received invalid input data: {data}.');
}
$output = $this->doTransform($data, $context);
if (!$this->conformsToOutputShape($output, $context)) {
$throw('Adaptor {class} returned invalid output data: {data}');
}
return $output;
}
/**
* Basic transformation from a shape into another shape.
*
* This method does not include validations since they are handled in the
* calling method.
*
* @param mixed $data
* The data to transform.
* @param \Shaper\Util\Context $context
* Additional information that will affect how the data is transformed.
*
* @return mixed
* The data in the new shape.
*
* @throws \TypeError
* When the transformation cannot be applied.
*/
abstract protected function doTransform($data, Context $context);
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Shaper\Transformation;
use Shaper\Util\Context;
interface TransformationValidationInterface {
/**
* Checks if the data provided can be transformed by the validator.
*
* @param mixed $data
* The data to check.
* @param \Shaper\Util\Context $context
* Additional information that will affect applicability.
*
* @return bool
* TRUE if the transformation can be used with the supplied data.
*/
public function conformsToExpectedInputShape($data, ?Context $context = NULL);
/**
* Checks if the transformed data conforms to the expected shape.
*
* @param mixed $data
* The data to check.
* @param \Shaper\Util\Context $context
* Additional information that will affect applicability.
*
* @return bool
* TRUE if the transformed data conforms to the expected shape.
*/
public function conformsToOutputShape($data, ?Context $context = NULL);
/**
* The validator for the input data.
*
* @return \Shaper\Validator\ValidateableInterface
*/
public function getInputValidator();
/**
* The validator for the output data.
*
* @return \Shaper\Validator\ValidateableInterface
*/
public function getOutputValidator();
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Shaper\Transformation;
use Shaper\Util\Context;
trait TransformationValidationTrait {
/**
* {@inheritdoc}
*/
public function conformsToExpectedInputShape($data, ?Context $context = NULL) {
return $this->getInputValidator()->isValid($data);
}
/**
* {@inheritdoc}
*/
public function conformsToOutputShape($data, ?Context $context = NULL) {
return $this->getOutputValidator()->isValid($data);
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace Shaper\Transformation;
use Shaper\Util\Context;
class TransformationsQueue extends \SplQueue implements TransformationInterface, TransformationValidationInterface {
use TransformationValidationTrait;
/**
* {@inheritdoc}
*/
public function transform($data, ?Context $context = NULL) {
if (!isset($context)) {
$context = new Context();
}
$output = $data;
foreach ($this as $transformation) {
$output = $transformation->transform($output, $context);
}
return $output;
}
/**
* {@inheritdoc}
*/
public function getInputValidator() {
/** @var \Shaper\Transformation\TransformationValidationInterface $first_transformation */
$first_transformation = $this->bottom();
return $first_transformation->getInputValidator();
}
/**
* {@inheritdoc}
*/
public function getOutputValidator() {
/** @var \Shaper\Transformation\TransformationValidationInterface $last_transformation */
$last_transformation = $this->top();
return $last_transformation->getOutputValidator();
}
}

View File

@@ -0,0 +1,5 @@
<?php
namespace Shaper\Util;
class Context extends \ArrayObject {}

View File

@@ -0,0 +1,25 @@
<?php
/**
* Created by PhpStorm.
* User: e0ipso
* Date: 27/02/2018
* Time: 13:37
*/
namespace Shaper\Validator;
/**
* Validator that accepts everything.
*
* @package Shaper
*/
class AcceptValidator extends ValidateableBase {
/**
* {@inheritdoc}
*/
public function isValid($data) {
return TRUE;
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Shaper\Validator;
class CollectionOfValidators extends ValidateableBase {
/**
* The name of the class or interface the data must comply.
*
* @var string
*/
protected $itemValidator;
/**
* InstanceofValidator constructor.
*
* @param ValidateableInterface $item_validator
* The validator to apply to each item.
*
* @throws \TypeError
* If the class or interface does not exist.
*/
public function __construct(ValidateableInterface $item_validator) {
$this->itemValidator = $item_validator;
}
/**
* {@inheritdoc}
*/
public function isValid($data) {
$this->resetErrors();
if (!is_array($data)) {
array_push($this->errors, 'Collection of validators only applies on data arrays.');
return FALSE;
}
// The collection is valid if all the items are valid.
return array_reduce($data, function ($is_valid, $item) {
$valid_item = TRUE;
$is_valid = $is_valid && ($valid_item = $this->itemValidator->isValid($item));
if (!$valid_item) {
$this->errors = array_merge($this->errors, $this->itemValidator->getErrors());
}
return $is_valid;
}, TRUE);
}
}

View File

@@ -0,0 +1,51 @@
<?php
namespace Shaper\Validator;
class InstanceofValidator extends ValidateableBase {
/**
* The name of the class or interface the data must comply.
*
* @var string
*/
protected $supportedClassOrInterface;
/**
* InstanceofValidator constructor.
*
* @param string $supported_class_or_interface
* The class or interface. It must exist.
*
* @throws \TypeError
* If the class or interface does not exist.
*/
public function __construct($supported_class_or_interface) {
if (
!class_exists($supported_class_or_interface) &&
!interface_exists($supported_class_or_interface)
) {
$message = sprintf('Class or interface %s does not exist.', $supported_class_or_interface);
throw new \TypeError($message);
}
$this->supportedClassOrInterface = $supported_class_or_interface;
}
/**
* {@inheritdoc}
*/
public function isValid($data) {
$this->resetErrors();
$is_valid = is_a($data, $this->supportedClassOrInterface);
if (!$is_valid) {
$message = sprintf(
'"%s" does not extend or implement "%s".',
is_object($data) ? get_class($data) : $data,
$this->supportedClassOrInterface
);
array_push($this->errors, $message);
}
return $is_valid;
}
}

View File

@@ -0,0 +1,113 @@
<?php
namespace Shaper\Validator;
use JsonSchema\Validator;
class JsonSchemaValidator extends ValidateableBase {
/**
* The JSON object with the schema.
*
* @var array
*/
protected $schema;
/**
* The schema validator.
*
* @var \JsonSchema\Validator
*/
protected $validator;
/**
* The check mode flag for the JSON Schema validator.
*
* @var int
*/
protected $checkMode;
/**
* JsonSchema constructor.
*
* @param array $schema
* The schema.
* @param \JsonSchema\Validator $validator
* The validator.
*/
public function __construct(?array $schema = NULL, ?Validator $validator = NULL, $mode = NULL) {
$this->schema = $schema;
$this->validator = $validator;
$this->checkMode = $mode;
}
/**
* Sets the validator.
*
* @param \JsonSchema\Validator $validator
* The object that checks the JSON Schema.
*/
public function setValidator(Validator $validator) {
$this->validator = $validator;
}
/**
* Transforms the schema into a JSON object.
*
* @return string
* The JSON object representation.
*/
public function toJSON() {
return json_encode($this->schema);
}
/**
* {@inheritdoc}
*/
public function isValid($data) {
$this->resetErrors();
if (!$this->validator) {
throw new \InvalidArgumentException('JSON Schema validator needs to be set using setValidator().');
}
$num_errors = $this->validator->validate($data, $this->schema, $this->checkMode);
if ($num_errors) {
$this->errors = array_merge($this->errors, $this->validator->getErrors());
}
return !$num_errors;
}
/**
* Avoid serializing the validator.
*
* @return array
* The names of the properties to serialize.
*/
public function __sleep() {
return ['schema', 'errors'];
}
/**
* Re-attach a validator on de-serialization.
*/
public function __wakeup() {
$this->setValidator(new Validator());
}
public function getErrors() {
if ($this->validator) {
return $this->validator->getErrors();
}
return parent::getErrors();
}
/**
* {@inheritdoc}
*/
public function resetErrors() {
if ($this->validator) {
$this->validator->reset();
}
$this->errors = [];
}
}

View File

@@ -0,0 +1,52 @@
<?php
namespace Shaper\Validator;
use JsonSchema\Validator;
class RegexpValidator extends ValidateableBase {
/**
* The name of the class or interface the data must comply.
*
* @var \Shaper\Validator\JsonSchemaValidator
*/
protected $stringValidator;
/**
* The regular expression.
*
* @var string
*/
protected $regexp;
/**
* InstanceofValidator constructor.
*
* @param string $regexp
* The regular expression (without delimiters) to check.
*/
public function __construct($regexp) {
$this->regexp = $regexp;
$this->stringValidator = new JsonSchemaValidator(['type' => 'string'], new Validator());
}
/**
* {@inheritdoc}
*/
public function isValid($data) {
$this->resetErrors();
$matches_regexp = $this->stringValidator->isValid($data) &&
preg_match('@' . $this->regexp . '@', $data);
if (!$matches_regexp) {
$message = sprintf(
'String "%s" does not match regular expression /%s/ as expected.',
$data,
$this->regexp
);
array_push($this->errors, $message);
}
return $matches_regexp;
}
}

View File

@@ -0,0 +1,23 @@
<?php
namespace Shaper\Validator;
abstract class ValidateableBase implements ValidateableInterface {
protected $errors = [];
/**
* {@inheritdoc}
*/
public function getErrors() {
return $this->errors;
}
/**
* {@inheritdoc}
*/
public function resetErrors() {
$this->errors = [];
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Shaper\Validator;
interface ValidateableInterface {
/**
* Checks that the provided data is valid.
*
* @param mixed $data
* The data to validate.
*
* @return bool
* TRUE if the data is valid. FALSE otherwise.
*/
public function isValid($data);
/**
* Get the eventual errors in case validation failed.
*
* @return array
* The list of errors that happened.
*/
public function getErrors();
/**
* Clears any reported errors.
*
* Should be used between validation checks.
*/
public function resetErrors();
}