Skip to content

Commit

Permalink
feat: implement serializer, use serializer to deserialize param conve…
Browse files Browse the repository at this point in the history
…rter objects
  • Loading branch information
shpran committed Oct 13, 2021
1 parent acf7b8e commit 09f10f2
Show file tree
Hide file tree
Showing 17 changed files with 377 additions and 58 deletions.
6 changes: 5 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@
"flow/jsonpath": "~0.5",
"jtl-software/opsgenie-client": "2.0.2",
"league/openapi-psr7-validator": "0.9",
"relay/relay": "~2.0"
"relay/relay": "~2.0",
"symfony/serializer": "~5.2.0",
"symfony/http-foundation": "^5.3",
"symfony/psr-http-message-bridge": "^2.1",
"symfony/property-access": "~5.0.0"
},
"autoload": {
"psr-4": {
Expand Down
4 changes: 3 additions & 1 deletion manifest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
use oat\tao\scripts\install\SetupMaintenanceService;
use oat\tao\scripts\install\InstallNotificationTable;
use oat\tao\scripts\install\RegisterTaskQueueServices;
use oat\tao\model\Serializer\SerializerServiceProvider;
use oat\tao\scripts\install\CreateWebhookEventLogTable;
use oat\tao\scripts\install\RegisterSignatureGenerator;
use oat\tao\scripts\install\RegisterActionAccessControl;
Expand All @@ -60,14 +61,14 @@
use oat\tao\scripts\install\RegisterResourceRelationService;
use oat\tao\scripts\install\RegisterValueCollectionServices;
use oat\tao\scripts\install\RegisterClassPropertyRemovedEvent;
use oat\tao\model\ParamConverter\ParamConverterServiceProvider;
use oat\tao\scripts\install\RegisterUserLockoutsEventListeners;
use oat\tao\scripts\install\RegisterClassPropertiesChangedEvent;
use oat\tao\scripts\install\RegisterClassPropertyRemovedListener;
use oat\tao\scripts\install\RegisterDataAccessControlChangedEvent;
use oat\tao\scripts\install\RegisterDataAccessControlChangedListener;
use oat\tao\scripts\install\RegisterClassPropertiesChangedEventListener;
use oat\tao\model\HttpFoundation\ServiceProvider\HttpFoundationServiceProvider;
use oat\tao\model\ParamConverter\ServiceProvider\ParamConverterServiceProvider;

$extpath = __DIR__ . DIRECTORY_SEPARATOR;

Expand Down Expand Up @@ -267,6 +268,7 @@
'structures' => $extpath . 'actions' . DIRECTORY_SEPARATOR . 'structures.xml',
],
'containerServiceProviders' => [
SerializerServiceProvider::class,
HttpFoundationServiceProvider::class,
ParamConverterServiceProvider::class,
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@
*/
class ParamConverter extends ConfigurationAnnotation
{
public const OPTION_CREATION_RULE = 'creationRule';

public const RULE_CREATE = 'create';
public const RULE_DESERIALIZE = 'deserialize';

/** @var string */
private $name;

Expand Down
70 changes: 70 additions & 0 deletions models/classes/ParamConverter/Context/ObjectFactoryContext.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

declare(strict_types=1);

namespace oat\tao\model\ParamConverter\Context;

use InvalidArgumentException;
use oat\tao\model\Context\AbstractContext;

class ObjectFactoryContext extends AbstractContext implements ObjectFactoryContextInterface
{
public const PARAM_CLASS = 'class';
public const PARAM_DATA = 'data';
public const PARAM_FORMAT = 'format';
public const PARAM_CONTEXT = 'context';

public function getClass(): string
{
return $this->getParameter(self::PARAM_CLASS);
}

public function getData(): array
{
return $this->getParameter(self::PARAM_DATA);
}

public function getFormat(): string
{
return $this->getParameter(self::PARAM_FORMAT, 'json');
}

public function getContext(): array
{
return $this->getParameter(self::PARAM_CONTEXT, []);
}

protected function getSupportedParameters(): array
{
return [
self::PARAM_CLASS,
self::PARAM_DATA,
self::PARAM_FORMAT,
self::PARAM_CONTEXT,
];
}

protected function validateParameter(string $parameter, $parameterValue): void
{
if (
in_array($parameter, [self::PARAM_CLASS, self::PARAM_FORMAT], true)
&& is_string($parameterValue)
) {
return;
}

if (
in_array($parameter, [self::PARAM_DATA, self::PARAM_CONTEXT], true)
&& is_array($parameterValue)
) {
return;
}

throw new InvalidArgumentException(
sprintf(
'Context parameter %s is not valid.',
$parameter
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace oat\tao\model\ParamConverter\Context;

interface ObjectFactoryContextInterface
{
public function getClass(): string;

public function getData(): array;

public function getFormat(): string;

public function getContext(): array;
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
use oat\tao\model\Context\AbstractContext;
use oat\tao\model\HttpFoundation\Request\RequestInterface;

class ParamConverterListenerContext extends AbstractContext
class ParamConverterListenerContext extends AbstractContext implements ParamConverterListenerContextInterface
{
public const PARAM_REQUEST = 'request';
public const PARAM_CONTROLLER = 'controller';
Expand All @@ -39,6 +39,21 @@ public function __construct(array $parameters)
parent::__construct($parameters);
}

public function getRequest(): RequestInterface
{
return $this->getParameter(self::PARAM_REQUEST);
}

public function getController(): string
{
return $this->getParameter(self::PARAM_CONTROLLER);
}

public function getMethod(): string
{
return $this->getParameter(self::PARAM_METHOD);
}

protected function getRequiredParameters(): array
{
return [
Expand All @@ -64,16 +79,12 @@ protected function validateParameter(string $parameter, $parameterValue): void
}

if (
$parameter === self::PARAM_CONTROLLER
&& (is_string($parameterValue) || is_object($parameterValue))
in_array($parameter, [self::PARAM_CONTROLLER, self::PARAM_METHOD], true)
&& is_string($parameterValue)
) {
return;
}

if ($parameter === self::PARAM_METHOD && is_string($parameterValue)) {
return;
}

throw new InvalidArgumentException(
sprintf(
'Context parameter %s is not valid.',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

declare(strict_types=1);

namespace oat\tao\model\ParamConverter\Context;

use oat\tao\model\HttpFoundation\Request\RequestInterface;

interface ParamConverterListenerContextInterface
{
public function getRequest(): RequestInterface;

public function getController(): string;

public function getMethod(): string;
}
4 changes: 2 additions & 2 deletions models/classes/ParamConverter/Event/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
namespace oat\tao\model\ParamConverter\Event;

use oat\oatbox\event\Event as BaseEvent;
use oat\tao\model\Context\ContextInterface;
use oat\tao\model\ParamConverter\Context\ParamConverterListenerContextInterface;

interface Event extends BaseEvent
{
public function getContext(): ContextInterface;
public function getContext(): ParamConverterListenerContextInterface;
}
8 changes: 4 additions & 4 deletions models/classes/ParamConverter/Event/ParamConverterEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,19 @@

namespace oat\tao\model\ParamConverter\Event;

use oat\tao\model\Context\ContextInterface;
use oat\tao\model\ParamConverter\Context\ParamConverterListenerContextInterface;

class ParamConverterEvent implements Event
{
/** @var ContextInterface */
/** @var ParamConverterListenerContextInterface */
private $context;

public function __construct(ContextInterface $context)
public function __construct(ParamConverterListenerContextInterface $context)
{
$this->context = $context;
}

public function getContext(): ContextInterface
public function getContext(): ParamConverterListenerContextInterface
{
return $this->context;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
use oat\tao\model\ParamConverter\Event\ParamConverterEvent;
use oat\tao\model\ParamConverter\Configuration\ParamConverter;
use oat\tao\model\ParamConverter\Configuration\ConfiguratorInterface;
use oat\tao\model\ParamConverter\Context\ParamConverterListenerContext;
use oat\tao\model\ParamConverter\Manager\ParamConverterManagerInterface;

class ParamConverterListener implements ListenerInterface
Expand Down Expand Up @@ -61,13 +60,12 @@ public function handleEvent(Event $event): void
}

$context = $event->getContext();
/** @var RequestInterface $request */
$request = $context->getParameter(ParamConverterListenerContext::PARAM_REQUEST);
$request = $context->getRequest();

$configurations = $this->extractConfigurations($request);

$controller = $context->getParameter(ParamConverterListenerContext::PARAM_CONTROLLER);
$method = $context->getParameter(ParamConverterListenerContext::PARAM_METHOD);
$controller = $context->getController();
$method = $context->getMethod();

// Automatically apply conversion for non-configured objects
if ($this->autoConvert && is_callable([$controller, $method])) {
Expand Down
71 changes: 71 additions & 0 deletions models/classes/ParamConverter/Factory/ObjectFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

declare(strict_types=1);

namespace oat\tao\model\ParamConverter\Factory;

use ReflectionClass;
use InvalidArgumentException;
use oat\tao\model\Serializer\SerializerInterface;
use oat\tao\model\ParamConverter\Context\ObjectFactoryContextInterface;

class ObjectFactory implements ObjectFactoryInterface
{
/** @var SerializerInterface */
private $serializer;

public function __construct(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}

public function create(ObjectFactoryContextInterface $context): object
{
$constructorArgs = [];
$data = $context->getData();

$reflectionClass = new ReflectionClass($context->getClass());
$constructor = $reflectionClass->getConstructor();

if ($constructor) {
foreach ($constructor->getParameters() as $constructorParameter) {
$constructorParameterName = $constructorParameter->getName();

if (array_key_exists($constructorParameterName, $data)) {
$constructorArgs[$constructorParameterName] = $data[$constructorParameterName];
unset($data[$constructorParameterName]);
}
}
}

$instance = $reflectionClass->newInstanceArgs($constructorArgs);

foreach ($data as $queryParameter => $value) {
if ($reflectionClass->hasMethod('set' . $queryParameter)) {
$reflectionClass
->getMethod('set' . $queryParameter)
->invoke($instance, $value);
} elseif ($reflectionClass->hasProperty($queryParameter)) {
$reflectionClass->getProperty($queryParameter)->setValue($instance, $value);
}
}

return $instance;
}

public function deserialize(ObjectFactoryContextInterface $context): object
{
$format = $context->getFormat();

if ($format !== 'json') {
throw new InvalidArgumentException('Currently, only the "json" format is supported.');
}

return $this->serializer->deserialize(
json_encode($context->getData()),
$context->getClass(),
$format,
$context->getContext()
);
}
}
14 changes: 14 additions & 0 deletions models/classes/ParamConverter/Factory/ObjectFactoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace oat\tao\model\ParamConverter\Factory;

use oat\tao\model\ParamConverter\Context\ObjectFactoryContextInterface;

interface ObjectFactoryInterface
{
public function create(ObjectFactoryContextInterface $context): object;

public function deserialize(ObjectFactoryContextInterface $context): object;
}
Loading

0 comments on commit 09f10f2

Please sign in to comment.