diff --git a/.gitignore b/.gitignore
index 1d5c172..178ff43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,55 +1,4 @@
-/*.pnproj
-/.idea
-.htaccess
-atlassian-ide-plugin.xml
-
-### Symfony template
-# Cache and logs (Symfony2)
-/app/cache/*
-/app/logs/*
-!app/cache/.gitkeep
-!app/logs/.gitkeep
-
-# Cache and logs (Symfony3)
-/var/*
-!/var/cache
-/var/cache/*
-!var/cache/.gitkeep
-!/var/logs
-/var/logs/*
-!var/logs/.gitkeep
-!/var/sessions
-/var/sessions/*
-!var/sessions/.gitkeep
-var/SymfonyRequirements.php
-
-# Parameters
-/app/config/parameters.yml
-/app/config/parameters.local.yml
-/app/config/parameters.ini
-
-# Managed by Composer
-/app/bootstrap.php.cache
-/var/bootstrap.php.cache
-/bin/*
-!bin/console
-bin/symfony_requirements
/vendor/
-
-# Assets and user uploads
-/web/bundles/
-/web/uploads/
-
-# PHPUnit
-/app/phpunit.xml
-
-# Build data
/build/
/target/
-
-# Any PHARs
-*.phar
-
-Thumbs.db
-
composer.lock
diff --git a/.scrutinizer.yml b/.scrutinizer.yml
index 7b7e67b..d0b662d 100644
--- a/.scrutinizer.yml
+++ b/.scrutinizer.yml
@@ -2,7 +2,7 @@ build:
tests:
override:
-
- command: phpunit --coverage-clover=build/clover.xml
+ command: JMS_BUNDLE=1 DOCTRINE_BUNDLE=1 phpunit --coverage-clover=build/clover.xml
coverage:
file: build/clover.xml
format: php-clover
diff --git a/.travis.yml b/.travis.yml
index 75401ab..a97ff9e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,36 +1,53 @@
language: php
php:
- - 5.5
- - 5.6
- - 7
- nightly
- - hhvm
+ - 7.1
+ - 7
+ - 5.6
+ - 5.5
+
+## Run on container environment
+sudo: false
+
+## Cache composer bits
+cache:
+ directories:
+ - $HOME/.composer/cache
env:
- - PACKAGES='symfony/symfony=2.7.*'
- - PACKAGES='symfony/symfony=2.8.*'
- - PACKAGES='symfony/symfony=3.1.*'
+ - PACKAGES='symfony/symfony=~3.4' STABILITY=dev
+ - PACKAGES='symfony/symfony=3.3.*'
- PACKAGES='symfony/symfony=3.2.*'
- - PACKAGES='symfony/symfony=~3.3@dev'
+ - PACKAGES='symfony/symfony=2.8.*'
+ - PACKAGES='symfony/symfony=2.7.*'
matrix:
+ fast_finish: true
include:
- - php: 5.5
- env: PACKAGES='symfony/symfony=2.7.*' deps='low'
+ - php: 7.1
+ env: PACKAGES='symfony/symfony=~4.0' STABILITY=dev
+ - php: nightly
+ env: PACKAGES='symfony/symfony=~4.0' STABILITY=dev
allow_failures:
- - php: hhvm
- php: nightly
+ - env: PACKAGES='symfony/symfony=~4.0' STABILITY=dev
before_install:
- travis_retry composer self-update
install:
- composer require --no-update ${PACKAGES}
- - if [ "$deps" = "no"] || [ -z "$deps" ]; then composer --prefer-source install; fi;
- - if [ "$deps" = "low" ]; then composer --prefer-source --prefer-lowest --prefer-stable update; composer --prefer-source install; fi;
+ - if [ "$STABILITY" = "dev" ]; then composer config minimum-stability dev; fi;
+ - composer --prefer-source install
script:
+ - rm -rf build
- mkdir -p build
- - vendor/bin/phpunit --colors -c phpunit.xml
+ - vendor/bin/phpunit --colors -c phpunit.xml --testsuite unit
+ - vendor/bin/phpunit --colors -c phpunit.xml --testsuite integration
+ - JMS_BUNDLE=1 vendor/bin/phpunit --colors -c phpunit.xml --testsuite integration
+ - SYMFONY_SERIALIZER=1 vendor/bin/phpunit --colors -c phpunit.xml --testsuite integration
+ - JMS_BUNDLE=1 DOCTRINE_BUNDLE=1 vendor/bin/phpunit --colors -c phpunit.xml --testsuite integration
+ - SYMFONY_SERIALIZER=1 DOCTRINE_BUNDLE=1 vendor/bin/phpunit --colors -c phpunit.xml --testsuite integration
diff --git a/Adapters/Builtin/BuiltinNormalizerAdapter.php b/Adapters/Builtin/BuiltinNormalizerAdapter.php
new file mode 100644
index 0000000..123d430
--- /dev/null
+++ b/Adapters/Builtin/BuiltinNormalizerAdapter.php
@@ -0,0 +1,18 @@
+hasParameter('jsonrpc_server.jms.handlers')) {
+ return;
+ }
+
+ foreach ($container->getParameter('jsonrpc_server.jms.handlers') as $handler => $emid) {
+ $this->configureRelationHandler($container, $handler, $emid);
+ }
+ }
+
+ private function configureRelationHandler(ContainerBuilder $builder, $handler, $emid)
+ {
+ if (!$builder->has($emid)) {
+ return;
+ }
+
+ $builder->register('jms_serializer.handler.relation.' . $handler, RelationsHandler::class)
+ ->setArguments([new Reference($emid)])
+ ->addTag(
+ 'jms_serializer.handler',
+ [
+ 'type' => $handler,
+ 'direction' => 'serialization',
+ 'format' => 'json',
+ 'method' => 'serializeRelation',
+ ]
+ )
+ ->addTag(
+ 'jms_serializer.handler',
+ [
+ 'type' => $handler,
+ 'direction' => 'deserialization',
+ 'format' => 'json',
+ 'method' => 'deserializeRelation',
+ ]
+ )
+ ->addTag(
+ 'jms_serializer.handler',
+ [
+ 'type' => $handler . '>',
+ 'direction' => 'serialization',
+ 'format' => 'json',
+ 'method' => 'serializeRelation',
+ ]
+ )
+ ->addTag(
+ 'jms_serializer.handler',
+ [
+ 'type' => $handler . '>',
+ 'direction' => 'deserialization',
+ 'format' => 'json',
+ 'method' => 'deserializeRelation',
+ ]
+ );
+ }
+}
diff --git a/Adapters/JMS/JmsNormalizerAdapter.php b/Adapters/JMS/JmsNormalizerAdapter.php
new file mode 100644
index 0000000..c1ab862
--- /dev/null
+++ b/Adapters/JMS/JmsNormalizerAdapter.php
@@ -0,0 +1,42 @@
+normalizer = $normalizer;
+ $this->contextFactory = $contextFactory;
+ }
+
+ /** {@inheritdoc} */
+ public function normalize($entity, array $context = [])
+ {
+ if (null === $entity) {
+ return null;
+ }
+
+ $jmsContext = $this->contextFactory->createSerializationContext();
+ $jmsContext->setGroups($context);
+
+ return $this->normalizer->toArray($entity, $jmsContext);
+ }
+}
diff --git a/Serializer/RelationsHandler.php b/Adapters/JMS/RelationsHandler.php
similarity index 64%
rename from Serializer/RelationsHandler.php
rename to Adapters/JMS/RelationsHandler.php
index 00d16ff..0073623 100644
--- a/Serializer/RelationsHandler.php
+++ b/Adapters/JMS/RelationsHandler.php
@@ -1,29 +1,30 @@
manager = $manager; }
-
+ public function __construct(ObjectManager $manager)
+ {
+ $this->manager = $manager;
+ }
- public function serializeRelation(JsonSerializationVisitor $visitor, $relation, array $type, Context $context)
+ public function serializeRelation(JsonSerializationVisitor $visitor, $relation)
{
if ($relation instanceof \Traversable) {
$relation = iterator_to_array($relation);
@@ -36,24 +37,7 @@ public function serializeRelation(JsonSerializationVisitor $visitor, $relation,
return $this->getSingleEntityRelation($relation);
}
- /**
- * @param $relation
- *
- * @return array|mixed
- */
- protected function getSingleEntityRelation($relation)
- {
- $metadata = $this->manager->getClassMetadata(get_class($relation));
-
- $ids = $metadata->getIdentifierValues($relation);
- if (!$metadata->isIdentifierComposite) {
- $ids = array_shift($ids);
- }
-
- return $ids;
- }
-
- public function deserializeRelation(JsonDeserializationVisitor $visitor, $relation, array $type, Context $context)
+ public function deserializeRelation(JsonDeserializationVisitor $visitor, $relation, array $type)
{
$className = isset($type['params'][0]['name']) ? $type['params'][0]['name'] : null;
@@ -65,7 +49,7 @@ public function deserializeRelation(JsonDeserializationVisitor $visitor, $relati
$metadata = $this->manager->getClassMetadata($className);
if (!is_array($relation)) {
- return $this->manager->getReference($className, $relation);
+ return $this->deserializeIdentifier($className, $relation);
}
$single = false;
@@ -77,14 +61,46 @@ public function deserializeRelation(JsonDeserializationVisitor $visitor, $relati
}
if ($single) {
- return $this->manager->getReference($className, $relation);
+ return $this->deserializeIdentifier($className, $relation);
}
$objects = [];
foreach ($relation as $idSet) {
- $objects[] = $this->manager->getReference($className, $idSet);
+ $objects[] = $this->deserializeIdentifier($className, $idSet);
}
return $objects;
}
+
+ /**
+ * @param $relation
+ *
+ * @return array|mixed
+ */
+ private function getSingleEntityRelation($relation)
+ {
+ $metadata = $this->manager->getClassMetadata(get_class($relation));
+
+ $ids = $metadata->getIdentifierValues($relation);
+ if (1 === count($metadata->getIdentifierFieldNames())) {
+ $ids = array_shift($ids);
+ }
+
+ return $ids;
+ }
+
+ /**
+ * @param string $className
+ * @param mixed $identifier
+ *
+ * @return object
+ */
+ private function deserializeIdentifier($className, $identifier)
+ {
+ if (method_exists($this->manager, 'getReference')) {
+ return $this->manager->getReference($className, $identifier);
+ }
+
+ return $this->manager->find($className, $identifier);
+ }
}
diff --git a/Adapters/Symfony/SymfonyNormalizerAdapter.php b/Adapters/Symfony/SymfonyNormalizerAdapter.php
new file mode 100644
index 0000000..54b9738
--- /dev/null
+++ b/Adapters/Symfony/SymfonyNormalizerAdapter.php
@@ -0,0 +1,32 @@
+normalizer = $normalizer;
+ }
+
+ /** {@inheritdoc} */
+ public function normalize($entity, array $context = [])
+ {
+ if (null === $entity) {
+ return null;
+ }
+
+ return $this->normalizer->normalize($entity, ['groups' => $context]);
+ }
+}
diff --git a/BankiruJsonRpcServerBundle.php b/BankiruJsonRpcServerBundle.php
new file mode 100644
index 0000000..c289549
--- /dev/null
+++ b/BankiruJsonRpcServerBundle.php
@@ -0,0 +1,26 @@
+addCompilerPass(new SymfonyAdapterConfigurationPass());
+ $container->addCompilerPass(new RelationHandlerPass());
+ }
+
+ public function getContainerExtension()
+ {
+ return new BankiruJsonRpcServerExtension();
+ }
+}
diff --git a/Controller/JsonRpcController.php b/Controller/JsonRpcController.php
index 0064990..8d04266 100644
--- a/Controller/JsonRpcController.php
+++ b/Controller/JsonRpcController.php
@@ -2,6 +2,7 @@
namespace Bankiru\Api\JsonRpc\Controller;
+use Bankiru\Api\JsonRpc\Exception\InvalidRequestException;
use Bankiru\Api\JsonRpc\Exception\RpcMethodNotFoundException;
use Bankiru\Api\JsonRpc\Http\JsonRpcHttpResponse;
use Bankiru\Api\JsonRpc\Specification\JsonRpcRequest;
@@ -23,14 +24,15 @@ final class JsonRpcController extends RpcController
*
* @throws BadRequestHttpException
* @throws RpcMethodNotFoundException
+ * @throws InvalidRequestException
*/
public function jsonRpcAction(Request $request)
{
$request->attributes->set('_format', 'json');
$jsonrpc = json_decode($request->getContent());
- if (null === $jsonrpc || json_last_error() !== JSON_ERROR_NONE) {
- throw new BadRequestHttpException('Not an valid JSON request');
+ if ((!is_array($jsonrpc) && !is_object($jsonrpc)) || json_last_error() !== JSON_ERROR_NONE) {
+ throw new BadRequestHttpException('Not a valid JSON-RPC request');
}
$singleRequest = false;
@@ -41,6 +43,9 @@ public function jsonRpcAction(Request $request)
$responses = [];
foreach ($jsonrpc as $call) {
+ if (!$call instanceof \stdClass) {
+ throw InvalidRequestException::notAJsonRpc();
+ }
$response = $this->handle($call, $request->get('_route'));
if (null !== $response) {
$responses[] = $response;
@@ -59,7 +64,7 @@ public function jsonRpcAction(Request $request)
*/
protected function getResolver()
{
- return $this->get('jsonrpc.controller_resolver');
+ return $this->get('jsonrpc_server.controller_resolver');
}
/**
diff --git a/Controller/JsonRpcControllerNameParser.php b/Controller/JsonRpcControllerNameParser.php
index a4cb7ed..8aa63be 100644
--- a/Controller/JsonRpcControllerNameParser.php
+++ b/Controller/JsonRpcControllerNameParser.php
@@ -10,6 +10,6 @@ final class JsonRpcControllerNameParser extends RpcControllerNameParser
/** {@inheritdoc} */
protected function guessControllerClassName(BundleInterface $bundle, $controller)
{
- return $bundle->getNamespace().'\\JsonRpc\\'.$controller.'Controller';
+ return $bundle->getNamespace() . '\\JsonRpc\\' . $controller . 'Controller';
}
}
diff --git a/DependencyInjection/BankiruJsonRpcServerExtension.php b/DependencyInjection/BankiruJsonRpcServerExtension.php
new file mode 100644
index 0000000..254438a
--- /dev/null
+++ b/DependencyInjection/BankiruJsonRpcServerExtension.php
@@ -0,0 +1,89 @@
+load('jsonrpc.yml');
+
+ $config = $this->processConfiguration(new Configuration(), $configs);
+
+ $this->configureSecurity($container);
+ $this->configureBuiltinAdapter($container);
+ $this->configureJmsAdapter($container, $config);
+
+ if ($this->isConfigEnabled($container, $config['normalizer_listener'])) {
+ $container->register('jsonrpc_server.response_listener.normalizer', NormalizingListener::class)
+ ->setPublic(true)
+ ->setArguments([new Reference($config['normalizer_listener']['normalizer'])])
+ ->addTag(
+ 'kernel.event_listener',
+ [
+ 'event' => RpcEvents::VIEW,
+ 'method' => 'onPlainResponse',
+ 'priority' => 255,
+ ]
+ );
+ }
+ }
+
+ public function getAlias()
+ {
+ return 'jsonrpc_server';
+ }
+
+ /**
+ * @param ContainerBuilder $container
+ */
+ private function configureBuiltinAdapter(ContainerBuilder $container)
+ {
+ $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config/adapters'));
+
+ $loader->load('builtin.yml');
+ }
+
+ /**
+ * @param ContainerBuilder $container
+ * @param array $config
+ */
+ private function configureJmsAdapter(ContainerBuilder $container, array $config)
+ {
+ if (!in_array(JMSSerializerBundle::class, $container->getParameter('kernel.bundles'), true)) {
+ return;
+ }
+
+ $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config/adapters'));
+ $loader->load('jms.yml');
+
+ if (!$this->isConfigEnabled($container, $config['adapters']['jms'])) {
+ return;
+ }
+
+ $container->setParameter('jsonrpc_server.jms.handlers', (array)$config['adapters']['jms']['relation_handlers']);
+ }
+
+ /**
+ * @param ContainerBuilder $container
+ */
+ private function configureSecurity(ContainerBuilder $container)
+ {
+ if (in_array(SecurityBundle::class, $container->getParameter('kernel.bundles'), true)) {
+ $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
+ $loader->load('security.yml');
+ }
+ }
+}
diff --git a/DependencyInjection/Compiler/JmsDriverPass.php b/DependencyInjection/Compiler/JmsDriverPass.php
deleted file mode 100644
index de50fcf..0000000
--- a/DependencyInjection/Compiler/JmsDriverPass.php
+++ /dev/null
@@ -1,29 +0,0 @@
-has('doctrine')) {
- return;
- }
-
- $container->register('jms_serializer.driver.relation', HandledTypeDriver::class)
- ->setArguments(
- [
- new Reference('jms_serializer.metadata.doctrine_type_driver'),
- new Reference('annotation_reader'),
- ]
- );
-
- $container->setAlias('jms_serializer.metadata_driver', 'jms_serializer.driver.relation');
- }
-}
diff --git a/DependencyInjection/Compiler/SymfonyAdapterConfigurationPass.php b/DependencyInjection/Compiler/SymfonyAdapterConfigurationPass.php
new file mode 100644
index 0000000..0486e51
--- /dev/null
+++ b/DependencyInjection/Compiler/SymfonyAdapterConfigurationPass.php
@@ -0,0 +1,48 @@
+hasDefinition('serializer')) {
+ return;
+ }
+
+ if ($this->hasSymfonySerializer($container)) {
+ $this->configureSymfonyAdapter($container);
+ }
+ }
+
+ /**
+ * @param ContainerBuilder $container
+ */
+ private function configureSymfonyAdapter(ContainerBuilder $container)
+ {
+ $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../../Resources/config/adapters'));
+
+ $loader->load('symfony.yml');
+ }
+
+ /**
+ * @param ContainerBuilder $container
+ *
+ * @return bool
+ */
+ private function hasSymfonySerializer(ContainerBuilder $container)
+ {
+ $interfaces = class_implements(
+ $container->getParameterBag()->resolveValue($container->getDefinition('serializer')->getClass())
+ );
+
+ return in_array(NormalizerInterface::class, $interfaces, true);
+ }
+}
diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php
new file mode 100644
index 0000000..7a0a878
--- /dev/null
+++ b/DependencyInjection/Configuration.php
@@ -0,0 +1,53 @@
+root('jsonrpc_server');
+
+ $normListener = $root
+ ->children()
+ ->arrayNode('normalizer_listener')
+ ->canBeDisabled();
+
+ $normListener
+ ->children()
+ ->scalarNode('normalizer')
+ ->info('View listener normalizer service ID')
+ ->defaultValue('jsonrpc_server.builtin_adapter.normalizer');
+
+ $adapters = $root->children()->arrayNode('adapters')->addDefaultsIfNotSet();
+ $this->configureJms($adapters);
+
+ return $builder;
+ }
+
+ /**
+ * @param ArrayNodeDefinition $adapters
+ */
+ private function configureJms(ArrayNodeDefinition $adapters)
+ {
+ $jms = $adapters->children()->arrayNode('jms');
+
+ $jms->canBeEnabled();
+
+ $jms->children()
+ ->arrayNode('relation_handlers')
+ ->fixXmlConfig('relation_handler')
+ ->useAttributeAsKey('handler')
+ ->prototype('scalar')
+ ->info(
+ 'Key: Relation handler name (i.e. "Relation"), Value: service ID for relation handler entity manager'
+ )
+ ->isRequired();
+ }
+}
diff --git a/DependencyInjection/JsonRpcExtension.php b/DependencyInjection/JsonRpcExtension.php
deleted file mode 100644
index 3d587af..0000000
--- a/DependencyInjection/JsonRpcExtension.php
+++ /dev/null
@@ -1,68 +0,0 @@
-load('jsonrpc.yml');
- }
-
- /** {@inheritdoc} */
- public function process(ContainerBuilder $container)
- {
- if (!$container->has('doctrine')) {
- return;
- }
-
- $container->register('jms_serializer.handler.relation', RelationsHandler::class)
- ->setArguments([new Reference('doctrine.orm.entity_manager')])
- ->addTag(
- 'jms_serializer.handler',
- [
- 'type' => 'Relation',
- 'direction' => 'serialization',
- 'format' => 'json',
- 'method' => 'serializeRelation',
- ]
- )
- ->addTag(
- 'jms_serializer.handler',
- [
- 'type' => 'Relation',
- 'direction' => 'deserialization',
- 'format' => 'json',
- 'method' => 'deserializeRelation',
- ]
- )
- ->addTag(
- 'jms_serializer.handler',
- [
- 'type' => 'Relation>',
- 'direction' => 'serialization',
- 'format' => 'json',
- 'method' => 'serializeRelation',
- ]
- )
- ->addTag(
- 'jms_serializer.handler',
- [
- 'type' => 'Relation>',
- 'direction' => 'deserialization',
- 'format' => 'json',
- 'method' => 'deserializeRelation',
- ]
- );
- }
-}
diff --git a/Exception/InvalidRequestException.php b/Exception/InvalidRequestException.php
index 3d7b08d..8262aa3 100644
--- a/Exception/InvalidRequestException.php
+++ b/Exception/InvalidRequestException.php
@@ -21,4 +21,12 @@ public static function invalidVersion($expected, $actual)
sprintf('Invalid JSONRPC 2.0 Request. Version mismatch: %s expected, %s given', $expected, $actual)
);
}
+
+ public static function notAJsonRpc()
+ {
+ return self::create(
+ JsonRpcError::INVALID_REQUEST,
+ 'Not a JSONRPC 2.0 Request'
+ );
+ }
}
diff --git a/Exception/JsonRpcException.php b/Exception/JsonRpcException.php
index b27698a..d0687e7 100644
--- a/Exception/JsonRpcException.php
+++ b/Exception/JsonRpcException.php
@@ -18,7 +18,6 @@ public function __construct($message = '', $code = 0, Exception $previous = null
parent::__construct($message, $code, $previous);
}
-
/**
* @return JsonRpcErrorInterface
*/
diff --git a/Http/JsonRpcHttpResponse.php b/Http/JsonRpcHttpResponse.php
index 3291d46..af333c8 100644
--- a/Http/JsonRpcHttpResponse.php
+++ b/Http/JsonRpcHttpResponse.php
@@ -2,7 +2,7 @@
namespace Bankiru\Api\JsonRpc\Http;
-use Bankiru\Api\JsonRpc\JsonRpcBundle;
+use Bankiru\Api\JsonRpc\BankiruJsonRpcServerBundle;
use ScayTrase\Api\JsonRpc\JsonRpcErrorInterface;
use ScayTrase\Api\JsonRpc\JsonRpcResponseInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -24,18 +24,13 @@ public function __construct($jsonRpc = null, $status = 200, array $headers = [])
return;
}
- if (!is_array($jsonRpc)) {
- parent::__construct($this->formatJsonRpcResponse($jsonRpc), $status, $headers);
+ if (is_array($jsonRpc)) {
+ parent::__construct(array_map([$this, 'formatJsonRpcResponse'], $jsonRpc), $status, $headers);
return;
}
- $data = [];
- foreach ($jsonRpc as $response) {
- $data[] = $this->formatJsonRpcResponse($response);
- }
-
- parent::__construct($data, $status, $headers);
+ parent::__construct($this->formatJsonRpcResponse($jsonRpc), $status, $headers);
}
/**
@@ -46,21 +41,21 @@ public function __construct($jsonRpc = null, $status = 200, array $headers = [])
private function formatJsonRpcResponse(JsonRpcResponseInterface $jsonRpc)
{
$data = [
- 'jsonrpc' => JsonRpcBundle::VERSION,
+ 'jsonrpc' => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
'id' => $jsonRpc->getId(),
];
if ($jsonRpc->isSuccessful()) {
$data['result'] = $jsonRpc->getBody();
- return $data;
- } else {
- $error = $jsonRpc->getError();
- $data['error']['code'] = $error->getCode();
- $data['error']['message'] = $error->getMessage();
- $data['error']['data'] = $error instanceof JsonRpcErrorInterface ? $error->getData() : null;
-
return $data;
}
+
+ $error = $jsonRpc->getError();
+ $data['error']['code'] = $error->getCode();
+ $data['error']['message'] = $error->getMessage();
+ $data['error']['data'] = $error instanceof JsonRpcErrorInterface ? $error->getData() : null;
+
+ return $data;
}
}
diff --git a/JsonRpcBundle.php b/JsonRpcBundle.php
deleted file mode 100644
index 554cdb9..0000000
--- a/JsonRpcBundle.php
+++ /dev/null
@@ -1,19 +0,0 @@
-addCompilerPass(new JmsDriverPass(), PassConfig::TYPE_BEFORE_REMOVING);
- }
-}
diff --git a/Listener/AccessDeniedExceptionListener.php b/Listener/AccessDeniedExceptionListener.php
new file mode 100644
index 0000000..f88907e
--- /dev/null
+++ b/Listener/AccessDeniedExceptionListener.php
@@ -0,0 +1,34 @@
+getRequest();
+ if (!$request instanceof JsonRpcRequestInterface) {
+ return;
+ }
+
+ $exception = $event->getException();
+
+ if (!$exception instanceof AccessDeniedException) {
+ return;
+ }
+
+ $event->setException(
+ JsonRpcException::create(
+ JsonRpcError::METHOD_NOT_FOUND,
+ $exception->getMessage(),
+ $exception->getTrace()
+ )
+ );
+ }
+}
diff --git a/Listener/ExceptionHandlerListener.php b/Listener/ExceptionHandlerListener.php
index 535b5bc..0283f00 100644
--- a/Listener/ExceptionHandlerListener.php
+++ b/Listener/ExceptionHandlerListener.php
@@ -13,15 +13,17 @@
final class ExceptionHandlerListener
{
- private $debug = false;
+ private $debug;
/**
* ExceptionHandlerListener constructor.
*
* @param bool $debug
*/
- public function __construct($debug) { $this->debug = (bool)$debug; }
-
+ public function __construct($debug = false)
+ {
+ $this->debug = (bool)$debug;
+ }
public function onJsonRpcException(GetExceptionResponseEvent $event)
{
@@ -31,18 +33,21 @@ public function onJsonRpcException(GetExceptionResponseEvent $event)
}
$exception = $event->getException();
+
if ($exception instanceof InvalidMethodParametersException) {
$exception =
JsonRpcException::create(
JsonRpcError::INVALID_PARAMS,
$exception->getMessage(),
- $exception->getTrace());
+ $exception->getTrace()
+ );
} elseif ($exception instanceof MethodNotFoundException) {
$exception =
JsonRpcException::create(
JsonRpcError::METHOD_NOT_FOUND,
$exception->getMessage(),
- $exception->getTrace());
+ $exception->getTrace()
+ );
}
if ($exception instanceof JsonRpcExceptionInterface) {
diff --git a/Listener/HttpExceptionListener.php b/Listener/HttpExceptionListener.php
index 40018f8..fe9a0ca 100644
--- a/Listener/HttpExceptionListener.php
+++ b/Listener/HttpExceptionListener.php
@@ -6,20 +6,8 @@
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
-class HttpExceptionListener
+final class HttpExceptionListener
{
- private $debug = false;
-
- /**
- * ExceptionHandlerListener constructor.
- *
- * @param bool $debug
- */
- public function __construct($debug)
- {
- $this->debug = (bool)$debug;
- }
-
public function onJsonRpcException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
diff --git a/Listener/NormalizingListener.php b/Listener/NormalizingListener.php
new file mode 100644
index 0000000..94d1dba
--- /dev/null
+++ b/Listener/NormalizingListener.php
@@ -0,0 +1,49 @@
+normalizer = $normalizer;
+ }
+
+ public function onPlainResponse(ViewEvent $event)
+ {
+ $request = $event->getRequest();
+ $response = $event->getResponse();
+
+ // No need to perform JSON-RPC serialization here
+ if (!$request instanceof RichJsonRpcRequest || $request->isNotification()) {
+ return;
+ }
+
+ // Response is already properly formatted
+ if ($response instanceof JsonRpcResponseInterface) {
+ return;
+ }
+
+ $content = $event->getResponse();
+ if (!is_scalar($content) && null !== $content) {
+ $content = $this->normalizer->normalize($content, $request->getAttributes()->get('_context'));
+ }
+
+ $event->setResponse($content);
+ }
+}
diff --git a/Listener/NotificationResponseListener.php b/Listener/NotificationResponseListener.php
index a04bf60..a2e9c1b 100644
--- a/Listener/NotificationResponseListener.php
+++ b/Listener/NotificationResponseListener.php
@@ -17,7 +17,7 @@ final class NotificationResponseListener
*/
public function onNullResponse(ViewEvent $event)
{
- $request = $event->getRequest();
+ $request = $event->getRequest();
if (!$request instanceof JsonRpcRequestInterface) {
return;
diff --git a/Listener/SerializedJsonRpcResponseListener.php b/Listener/SerializedJsonRpcResponseListener.php
deleted file mode 100644
index 68f9c6f..0000000
--- a/Listener/SerializedJsonRpcResponseListener.php
+++ /dev/null
@@ -1,86 +0,0 @@
-serializer = $serializer; }
-
- public function onPlainResponse(ViewEvent $event)
- {
- $request = $event->getRequest();
- $response = $event->getResponse();
-
- // No need to perform JSON-RPC serialization here
- if (!$request instanceof JsonRpcRequestInterface || $request->isNotification()) {
- return;
- }
-
- // Response is already properly formatted
- if ($response instanceof JsonRpcResponseInterface) {
- return;
- }
-
- $response = new JsonRpcResponse(
- $request->getId(),
- json_decode(
- $this->serializer->serialize(
- $event->getResponse(),
- 'json',
- $this->createSerializerContext($event)
- )
- )
- );
- $event->setResponse($response);
-
- }
-
- /**
- * @param ViewEvent $event
- *
- * @return SerializationContext
- * @throws \LogicException
- */
- private function createSerializerContext(ViewEvent $event)
- {
- $context = SerializationContext::create();
- $context->setSerializeNull(true);
- $attributes = $event->getRequest()->getAttributes();
- $defaults = $attributes->get('_with_default_context', true);
-
- if (!$defaults && (false === $attributes->get('_context', false))) {
- throw new \LogicException(
- 'Could not perform object serialization as no default context allowed and no custom set'
- );
- }
-
- $groups = [];
- if ($defaults) {
- $groups[] = 'Default';
- }
- if (false !== $attributes->get('_context', false)) {
- foreach ((array)$attributes->get('_context') as $group) {
- $groups[] = $group;
- }
- }
-
- $context->setGroups($groups);
-
- return $context;
- }
-}
diff --git a/Listener/ViewListener.php b/Listener/ViewListener.php
new file mode 100644
index 0000000..1c951bc
--- /dev/null
+++ b/Listener/ViewListener.php
@@ -0,0 +1,31 @@
+getRequest();
+ $response = $event->getResponse();
+
+ // No need to perform JSON-RPC serialization here
+ if (!$request instanceof RichJsonRpcRequest || $request->isNotification()) {
+ return;
+ }
+
+ // Response is already properly formatted
+ if ($response instanceof JsonRpcResponseInterface) {
+ return;
+ }
+
+ $response = new JsonRpcResponse($request->getId(), $response);
+
+ $event->setResponse($response);
+ }
+}
diff --git a/NormalizerInterface.php b/NormalizerInterface.php
new file mode 100644
index 0000000..4ed0fd0
--- /dev/null
+++ b/NormalizerInterface.php
@@ -0,0 +1,16 @@
+setJsonRpcError(
new JsonRpcError(
@@ -44,9 +49,31 @@ $execption->setJsonRpcError(
(object)['debug_data' => 'some debug data']
)
);
+```
+
+Some exceptions are handled in a more specific manner
+
+* `AccessDeniedException` will result in `-32601` (method not found) json-rpc error code.
+* `MethodNotFoundException` will result in `-32601` (method not found) json-rpc error code.
+* `InvalidMethodParametersException` will result in `-32602` (invalid params) json-rpc error code
+
+## Configuration
+
+Configuration reference:
+
+```yaml
+jsonrpc_server:
+
+ # Normalizer listener service ID
+ normalizer_listener: jsonrpc_server.builtin_adapter.view_listener
+ adapters:
+ jms:
+ relation_handlers:
+ # Prototype: Key: Relation handler name (i.e. "Relation"), Value: service ID for relation handler entity manager
+ handler: ~
```
## Specification
-Refer to official JSON-RPC 2.0 specification at http://www.jsonrpc.org/specification
+Refer to official JSON-RPC 2.0 specification at http://www.jsonrpc.org/specification
diff --git a/Resources/config/adapters/builtin.yml b/Resources/config/adapters/builtin.yml
new file mode 100644
index 0000000..1add456
--- /dev/null
+++ b/Resources/config/adapters/builtin.yml
@@ -0,0 +1,4 @@
+services:
+ jsonrpc_server.builtin_adapter.normalizer:
+ class: Bankiru\Api\JsonRpc\Adapters\Builtin\BuiltinNormalizerAdapter
+ public: false
diff --git a/Resources/config/adapters/jms.yml b/Resources/config/adapters/jms.yml
new file mode 100644
index 0000000..65159d3
--- /dev/null
+++ b/Resources/config/adapters/jms.yml
@@ -0,0 +1,10 @@
+parameters:
+ jsonrpc_server.jms.handlers: []
+
+services:
+ jsonrpc_server.jms_adapter.normalizer:
+ class: Bankiru\Api\JsonRpc\Adapters\JMS\JmsNormalizerAdapter
+ arguments:
+ - "@jms_serializer"
+ - "@jms_serializer.serialization_context_factory"
+ public: false
diff --git a/Resources/config/adapters/symfony.yml b/Resources/config/adapters/symfony.yml
new file mode 100644
index 0000000..16a49d1
--- /dev/null
+++ b/Resources/config/adapters/symfony.yml
@@ -0,0 +1,5 @@
+services:
+ jsonrpc_server.symfony_adapter.normalizer:
+ class: Bankiru\Api\JsonRpc\Adapters\Symfony\SymfonyNormalizerAdapter
+ arguments:
+ - "@serializer"
diff --git a/Resources/config/jsonrpc.yml b/Resources/config/jsonrpc.yml
index 28f4155..76511f4 100644
--- a/Resources/config/jsonrpc.yml
+++ b/Resources/config/jsonrpc.yml
@@ -1,47 +1,47 @@
+parameters:
+ jsonrpc_server.debug: false
+
services:
- jsonrpc.controller_resolver:
+ jsonrpc_server.controller_resolver:
class: Bankiru\Api\Rpc\Routing\ControllerResolver\ControllerResolver
arguments:
- "@service_container"
- - "@jsonrpc.controller_name_parser"
+ - "@jsonrpc_server.controller_name_parser"
- "@?logger"
- jsonrpc.view.notification_response:
+ jsonrpc_server.view.notification_response:
class: Bankiru\Api\JsonRpc\Listener\NotificationResponseListener
tags:
- { name: kernel.event_listener, event: rpc.view, method: onNullResponse, priority: -255 }
- jsonrpc.view.notification_filter:
+ jsonrpc_server.view.notification_filter:
class: Bankiru\Api\JsonRpc\Listener\NotificationFilter
tags:
- { name: kernel.event_listener, event: rpc.response, method: filterNotificationResponse, priority: -255 }
- jsonrpc.view.serialize_response:
- class: Bankiru\Api\JsonRpc\Listener\SerializedJsonRpcResponseListener
- arguments:
- - "@jms_serializer"
+ jsonrpc_server.plain_view_listener:
+ class: Bankiru\Api\JsonRpc\Listener\ViewListener
tags:
- - { name: kernel.event_listener, event: rpc.view, method: onPlainResponse, priority: -254 }
+ - { name: kernel.event_listener, event: rpc.view, method: onPlainResponse, priority: -255 }
- jsonrpc.reponse_listener.match_id:
+ jsonrpc_server.response_listener.match_id:
class: Bankiru\Api\JsonRpc\Listener\IdMatcherListener
tags:
- { name: kernel.event_listener, event: rpc.response, method: onFilterResponse, priority: -254 }
- jsonrpc.controller_name_parser:
+ jsonrpc_server.controller_name_parser:
class: Bankiru\Api\JsonRpc\Controller\JsonRpcControllerNameParser
- parent: rpc.controller_name_parser
+ parent: rpc_server.controller_name_parser
- jsonrpc.exception_listener:
+ jsonrpc_server.exception_listener:
class: Bankiru\Api\JsonRpc\Listener\ExceptionHandlerListener
arguments:
- - "%kernel.debug%"
+ - "%jsonrpc_server.debug%"
tags:
- { name: kernel.event_listener, event: rpc.exception, method: onJsonRpcException }
- jsonrpc.http_exception_listener:
+ jsonrpc_server.http_exception_listener:
class: Bankiru\Api\JsonRpc\Listener\HttpExceptionListener
- arguments:
- - "%kernel.debug%"
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onJsonRpcException }
+
diff --git a/Resources/config/security.yml b/Resources/config/security.yml
new file mode 100644
index 0000000..46a93ea
--- /dev/null
+++ b/Resources/config/security.yml
@@ -0,0 +1,5 @@
+services:
+ jsonrpc_server.security.exception_listener:
+ class: Bankiru\Api\JsonRpc\Listener\AccessDeniedExceptionListener
+ tags:
+ - { name: kernel.event_listener, event: rpc.exception, method: onRpcException, priority: 255 }
diff --git a/Serializer/HandledType.php b/Serializer/HandledType.php
deleted file mode 100644
index e691ed8..0000000
--- a/Serializer/HandledType.php
+++ /dev/null
@@ -1,30 +0,0 @@
-handler = $handler; }
-
- /**
- * @return string
- */
- public function getHandler()
- {
- return $this->handler;
- }
-}
diff --git a/Serializer/HandledTypeDriver.php b/Serializer/HandledTypeDriver.php
deleted file mode 100644
index 3d3d4fd..0000000
--- a/Serializer/HandledTypeDriver.php
+++ /dev/null
@@ -1,71 +0,0 @@
-driver = $driver;
- $this->reader = $reader;
- }
-
- /**
- * @param \ReflectionClass $class
- *
- * @return \Metadata\ClassMetadata
- */
- public function loadMetadataForClass(\ReflectionClass $class)
- {
- $metadata = $this->driver->loadMetadataForClass($class);
- foreach ($metadata->propertyMetadata as $key => $propertyMetadata) {
- $type = $propertyMetadata->type['name'];
-
- if (!$propertyMetadata->reflection) {
- continue;
- }
-
- /** @var PropertyMetadata $propertyMetadata */
- /** @var HandledType $annot */
- $annot = $this->reader->getPropertyAnnotation($propertyMetadata->reflection, HandledType::class);
- if (!$annot) {
- continue;
- }
-
- $isCollection = false;
- $collectionType = null;
-
- if (in_array($type, ['array', 'ArrayCollection'], true)) {
- $isCollection = true;
- $collectionType = $type;
- $type = $propertyMetadata->type['params'][0]['name'];
- }
-
- $handler = $annot->handler ?: 'Relation';
-
- $newType = sprintf('%s<%s>', $handler, $type);
- if ($isCollection) {
- $newType = sprintf('%s<%s<%s>>', $collectionType, $handler, $type);
- }
-
- $propertyMetadata->setType($newType);
- }
-
- return $metadata;
- }
-}
diff --git a/Specification/JsonRpcRequest.php b/Specification/JsonRpcRequest.php
index f04b0bc..5ba298d 100644
--- a/Specification/JsonRpcRequest.php
+++ b/Specification/JsonRpcRequest.php
@@ -2,12 +2,12 @@
namespace Bankiru\Api\JsonRpc\Specification;
+use Bankiru\Api\JsonRpc\BankiruJsonRpcServerBundle;
use Bankiru\Api\JsonRpc\Exception\InvalidRequestException;
use Bankiru\Api\JsonRpc\Exception\JsonRpcException;
-use Bankiru\Api\JsonRpc\JsonRpcBundle;
-use ScayTrase\Api\JsonRpc\JsonRpcError;
use ScayTrase\Api\JsonRpc\JsonRpcRequestInterface;
+/** @internal */
final class JsonRpcRequest implements JsonRpcRequestInterface
{
/** @var string|null */
@@ -17,12 +17,6 @@ final class JsonRpcRequest implements JsonRpcRequestInterface
/** @var mixed|\stdClass */
private $parameters;
- /** @return bool True if request should not receive response from the server */
- public function isNotification()
- {
- return null === $this->id;
- }
-
/**
* @param \stdClass $source
*
@@ -44,8 +38,11 @@ public static function fromStdClass(\stdClass $source)
throw InvalidRequestException::missingFields($missing);
}
- if (JsonRpcBundle::VERSION !== $source->jsonrpc) {
- throw InvalidRequestException::invalidVersion(JsonRpcBundle::VERSION, $source->jsonrpc);
+ if (BankiruJsonRpcServerBundle::JSONRPC_VERSION !== $source->jsonrpc) {
+ throw InvalidRequestException::invalidVersion(
+ BankiruJsonRpcServerBundle::JSONRPC_VERSION,
+ $source->jsonrpc
+ );
}
$request->id = isset($source->id) ? $source->id : null;
@@ -55,6 +52,12 @@ public static function fromStdClass(\stdClass $source)
return $request;
}
+ /** {@inheritdoc} */
+ public function isNotification()
+ {
+ return null === $this->id;
+ }
+
/** {@inheritdoc} */
public function jsonSerialize()
{
@@ -69,7 +72,7 @@ public function jsonSerialize()
/** {@inheritdoc} */
public function getVersion()
{
- return JsonRpcBundle::VERSION;
+ return BankiruJsonRpcServerBundle::JSONRPC_VERSION;
}
/** @return string */
@@ -78,13 +81,13 @@ public function getMethod()
return $this->method;
}
- /** @return array */
+ /** {@inheritdoc} */
public function getParameters()
{
return $this->parameters;
}
- /** @return int|null Id. if not a notification and id is not set - id should be automatically generated */
+ /** {@inheritdoc} */
public function getId()
{
return $this->id;
diff --git a/Specification/JsonRpcResponse.php b/Specification/JsonRpcResponse.php
index 8edaefe..3ee27e4 100644
--- a/Specification/JsonRpcResponse.php
+++ b/Specification/JsonRpcResponse.php
@@ -2,10 +2,11 @@
namespace Bankiru\Api\JsonRpc\Specification;
-use Bankiru\Api\JsonRpc\JsonRpcBundle;
+use Bankiru\Api\JsonRpc\BankiruJsonRpcServerBundle;
use ScayTrase\Api\JsonRpc\JsonRpcResponseInterface;
use ScayTrase\Api\Rpc\RpcErrorInterface;
+/** @internal */
final class JsonRpcResponse implements JsonRpcResponseInterface
{
/** @var string */
@@ -29,22 +30,17 @@ public function __construct($id = null, $body = null, RpcErrorInterface $error =
$this->error = $error;
}
-
- /**
- * @return string JSON-RPC version
- */
+ /** {@inheritdoc} */
public function getVersion()
{
- return JsonRpcBundle::VERSION;
+ return BankiruJsonRpcServerBundle::JSONRPC_VERSION;
}
- /**
- * {@inheritdoc}
- */
+ /** {@inheritdoc} */
public function jsonSerialize()
{
$result = [
- self::VERSION_FIELD => JsonRpcBundle::VERSION,
+ self::VERSION_FIELD => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
self::ID_FIELD => $this->getId(),
];
@@ -59,25 +55,25 @@ public function jsonSerialize()
return $result;
}
- /** @return string|null Response ID or null for notification pseudo-response */
+ /** {@inheritdoc} */
public function getId()
{
return $this->id;
}
- /** @return bool */
+ /** {@inheritdoc} */
public function isSuccessful()
{
return $this->getError() === null;
}
- /** @return RpcErrorInterface|null */
+ /** {@inheritdoc} */
public function getError()
{
return $this->error;
}
- /** @return \stdClass|\stdClass[]|null */
+ /** {@inheritdoc} */
public function getBody()
{
return $this->body;
diff --git a/Specification/RichJsonRpcRequest.php b/Specification/RichJsonRpcRequest.php
index a462ee5..6c3e384 100644
--- a/Specification/RichJsonRpcRequest.php
+++ b/Specification/RichJsonRpcRequest.php
@@ -2,12 +2,12 @@
namespace Bankiru\Api\JsonRpc\Specification;
-use Bankiru\Api\JsonRpc\JsonRpcBundle;
-use Bankiru\Api\Rpc\Http\RequestInterface;
+use Bankiru\Api\JsonRpc\BankiruJsonRpcServerBundle;
+use Bankiru\Api\Rpc\RpcRequestInterface;
use ScayTrase\Api\JsonRpc\JsonRpcRequestInterface;
use Symfony\Component\HttpFoundation\ParameterBag;
-final class RichJsonRpcRequest implements RequestInterface, JsonRpcRequestInterface
+final class RichJsonRpcRequest implements RpcRequestInterface, JsonRpcRequestInterface
{
/** @var JsonRpcRequestInterface */
private $request;
@@ -23,11 +23,7 @@ final class RichJsonRpcRequest implements RequestInterface, JsonRpcRequestInterf
public function __construct(JsonRpcRequestInterface $request, ParameterBag $attributes = null)
{
$this->request = $request;
- $this->attributes = $attributes;
-
- if (null === $this->attributes) {
- $this->attributes = new ParameterBag();
- }
+ $this->attributes = $attributes ?: new ParameterBag();
}
/** {@inheritdoc} */
@@ -56,7 +52,7 @@ public function jsonSerialize()
/** {@inheritdoc} */
public function getVersion()
{
- return JsonRpcBundle::VERSION;
+ return BankiruJsonRpcServerBundle::JSONRPC_VERSION;
}
/** {@inheritdoc} */
diff --git a/Test/DependencyInjection/JsonRpcTestExtension.php b/Test/DependencyInjection/JsonRpcTestExtension.php
deleted file mode 100644
index 590ff18..0000000
--- a/Test/DependencyInjection/JsonRpcTestExtension.php
+++ /dev/null
@@ -1,58 +0,0 @@
-getExtensions() as $name => $extension) {
- switch ($name) {
- case 'rpc':
- $container->prependExtensionConfig(
- $name,
- [
- 'router' => [
- 'endpoints' => [
- 'test' => [
- 'path' => '/test/',
- 'resources' => '@JsonRpcTestBundle/Resources/config/jsonrpc_routes.yml',
- 'defaults' => [
- '_controller' => 'JsonRpcBundle:JsonRpc:jsonRpc',
- '_format' => 'json',
- ],
- ],
- 'test_private' => [
- 'path' => '/test/private/',
- 'defaults' => [
- '_controller' => 'JsonRpcBundle:JsonRpc:jsonRpc',
- '_format' => 'json',
- ],
- 'resources' => [
- '@JsonRpcTestBundle/Resources/config/jsonrpc_routes.yml',
- '@JsonRpcTestBundle/Resources/config/jsonrpc_private.yml',
- ],
- ],
- ],
- ],
- ]
- );
- break;
- }
- }
- }
-}
diff --git a/Test/Entity/SampleEntity.php b/Test/Entity/SampleEntity.php
index 412929a..ce679db 100644
--- a/Test/Entity/SampleEntity.php
+++ b/Test/Entity/SampleEntity.php
@@ -2,33 +2,14 @@
namespace Bankiru\Api\JsonRpc\Test\Entity;
-use JMS\Serializer\Annotation\Expose;
-use JMS\Serializer\Annotation\Groups;
-use JMS\Serializer\Annotation\SerializedName;
-use JMS\Serializer\Annotation\Since;
-use JMS\Serializer\Annotation\Type;
-
-class SampleEntity
+class SampleEntity implements \JsonSerializable
{
- /**
- * @var int|null
- */
+ /** @var int|null */
private $id;
- /**
- * @var string
- * @Type("string")
- * @SerializedName("sample_payload")
- * @Expose()
- */
+ /** @var string */
private $payload;
- /**
- * @var string
- * @Type("string")
- * @SerializedName("private_payload")
- * @Expose()
- * @Groups({"private"})
- * @Since("0.1")
- */
+
+ /** @var string */
private $secret;
/**
@@ -57,4 +38,13 @@ public function getPayload()
{
return $this->payload;
}
+
+ /** {@inheritdoc} */
+ public function jsonSerialize()
+ {
+ return [
+ 'id' => $this->id,
+ 'sample_payload' => $this->payload,
+ ];
+ }
}
diff --git a/Test/JsonRpc/AnnotationController.php b/Test/JsonRpc/AnnotationController.php
index 7580c1e..2b78c39 100644
--- a/Test/JsonRpc/AnnotationController.php
+++ b/Test/JsonRpc/AnnotationController.php
@@ -6,12 +6,9 @@
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
/**
- * Class AnnotationController
- *
- * @package Bankiru\Api\JsonRpc\Test\JsonRpc
* @Method("annotation")
*/
-class AnnotationController extends Controller
+final class AnnotationController extends Controller
{
/**
* @return array
diff --git a/Test/JsonRpc/FailingController.php b/Test/JsonRpc/FailingController.php
index d14d518..9d0a132 100644
--- a/Test/JsonRpc/FailingController.php
+++ b/Test/JsonRpc/FailingController.php
@@ -2,7 +2,7 @@
namespace Bankiru\Api\JsonRpc\Test\JsonRpc;
-class FailingController
+final class FailingController
{
public function failureAction()
{
diff --git a/Test/JsonRpc/SecurityController.php b/Test/JsonRpc/SecurityController.php
new file mode 100644
index 0000000..990441a
--- /dev/null
+++ b/Test/JsonRpc/SecurityController.php
@@ -0,0 +1,30 @@
+ true];
+ }
+
+ /**
+ * @Method("private")
+ * @Security("is_granted('IS_AUTHENTICATED_FULLY')")
+ */
+ public function privateAction()
+ {
+ return ['success' => true];
+ }
+}
diff --git a/Test/JsonRpc/TestController.php b/Test/JsonRpc/TestController.php
index a41c980..2405f2e 100644
--- a/Test/JsonRpc/TestController.php
+++ b/Test/JsonRpc/TestController.php
@@ -6,7 +6,7 @@
use Bankiru\Api\JsonRpc\Test\Entity\SampleEntity;
use ScayTrase\Api\JsonRpc\JsonRpcRequestInterface;
-class TestController
+final class TestController
{
public function sampleAction(JsonRpcRequestInterface $request)
{
diff --git a/Test/JsonRpcTestBundle.php b/Test/JsonRpcTestBundle.php
index 912ea2c..ccf8185 100644
--- a/Test/JsonRpcTestBundle.php
+++ b/Test/JsonRpcTestBundle.php
@@ -4,6 +4,7 @@
use Symfony\Component\HttpKernel\Bundle\Bundle;
-class JsonRpcTestBundle extends Bundle
+/** @internal */
+final class JsonRpcTestBundle extends Bundle
{
}
diff --git a/Test/Kernel/TestKernel.php b/Test/Kernel/TestKernel.php
new file mode 100644
index 0000000..a904a33
--- /dev/null
+++ b/Test/Kernel/TestKernel.php
@@ -0,0 +1,90 @@
+getName() . '/cache';
+ }
+
+ public function getLogDir()
+ {
+ return __DIR__ . '/../../build/' . $this->getName() . '/log';
+ }
+
+ public function registerContainerConfiguration(LoaderInterface $loader)
+ {
+ $loader->load(__DIR__ . '/config.yml');
+
+ if (false !== getenv('JMS_BUNDLE')) {
+ $loader->load(__DIR__ . '/config_jms.yml');
+ }
+
+ if (false !== getenv('SYMFONY_SERIALIZER')) {
+ $loader->load(__DIR__ . '/config_symfony.yml');
+ }
+
+ if (false !== getenv('DOCTRINE_BUNDLE')) {
+ $loader->load(__DIR__ . '/config_doctrine.yml');
+ }
+ }
+
+ public function getName()
+ {
+ $name = 'jsorpc_test';
+
+ if (false !== getenv('JMS_BUNDLE')) {
+ $name .= '_jms';
+ }
+
+ if (false !== getenv('SYMFONY_SERIALIZER')) {
+ $name .= '_symfony';
+ }
+
+ if (false !== getenv('DOCTRINE_BUNDLE')) {
+ $name .= '_doctrine';
+ }
+
+ return $name;
+ }
+
+ public function getEnvironment()
+ {
+ return 'test';
+ }
+}
diff --git a/Test/Kernel/config.yml b/Test/Kernel/config.yml
new file mode 100644
index 0000000..d0ce868
--- /dev/null
+++ b/Test/Kernel/config.yml
@@ -0,0 +1,47 @@
+framework:
+ test: ~
+ secret: test
+ router:
+ resource: "%kernel.root_dir%/routing.yml"
+
+services:
+ logger:
+ class: Psr\Log\NullLogger
+
+security:
+ providers:
+ in_memory:
+ memory: ~
+
+ firewalls:
+ main:
+ anonymous: ~
+
+ access_control:
+ - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }
+
+jsonrpc_server:
+ normalizer_listener:
+ enabled: true
+ adapters:
+ jms:
+ relation_handlers:
+ Relation: doctrine.orm.entity_manager
+
+rpc_server:
+ router:
+ endpoints:
+ test:
+ path: /test/
+ resources: '@JsonRpcTestBundle/Resources/config/jsonrpc_routes.yml'
+ defaults:
+ _controller : BankiruJsonRpcServerBundle:JsonRpc:jsonRpc
+ _format: json
+ test_private:
+ path: /test/private/
+ defaults:
+ _controller : BankiruJsonRpcServerBundle:JsonRpc:jsonRpc
+ _format: json
+ resources:
+ - '@JsonRpcTestBundle/Resources/config/jsonrpc_routes.yml'
+ - '@JsonRpcTestBundle/Resources/config/jsonrpc_private.yml'
diff --git a/Test/Kernel/config_doctrine.yml b/Test/Kernel/config_doctrine.yml
new file mode 100644
index 0000000..4daa5a5
--- /dev/null
+++ b/Test/Kernel/config_doctrine.yml
@@ -0,0 +1,7 @@
+doctrine:
+ dbal:
+ driver: pdo_sqlite
+ memory: true
+ orm:
+ auto_mapping: true
+ auto_generate_proxy_classes: true
diff --git a/Test/Kernel/config_jms.yml b/Test/Kernel/config_jms.yml
new file mode 100644
index 0000000..fa7a916
--- /dev/null
+++ b/Test/Kernel/config_jms.yml
@@ -0,0 +1,10 @@
+framework:
+ translator: ~
+
+jms_serializer:
+ metadata:
+ auto_detection: true
+
+jsonrpc_server:
+ normalizer_listener:
+ normalizer: jsonrpc_server.jms_adapter.normalizer
diff --git a/Test/Kernel/config_symfony.yml b/Test/Kernel/config_symfony.yml
new file mode 100644
index 0000000..440a8b3
--- /dev/null
+++ b/Test/Kernel/config_symfony.yml
@@ -0,0 +1,6 @@
+framework:
+ serializer: ~
+
+jsonrpc_server:
+ normalizer_listener:
+ normalizer: jsonrpc_server.symfony_adapter.normalizer
diff --git a/Test/Tests/Fixtures/routing.yml b/Test/Kernel/routing.yml
similarity index 100%
rename from Test/Tests/Fixtures/routing.yml
rename to Test/Kernel/routing.yml
diff --git a/Test/Resources/config/doctrine/SampleEntity.orm.yml b/Test/Resources/config/doctrine/SampleEntity.orm.yml
new file mode 100644
index 0000000..48d9977
--- /dev/null
+++ b/Test/Resources/config/doctrine/SampleEntity.orm.yml
@@ -0,0 +1,10 @@
+Bankiru\Api\JsonRpc\Test\Entity\SampleEntity:
+ type: entity
+ id:
+ id:
+ type: integer
+ generator:
+ strategy: AUTO
+ fields:
+ payload: {type: string}
+ secret: {type: string}
diff --git a/Test/Resources/config/serializer/Entity.SampleEntity.yml b/Test/Resources/config/serializer/Entity.SampleEntity.yml
new file mode 100644
index 0000000..bbfff37
--- /dev/null
+++ b/Test/Resources/config/serializer/Entity.SampleEntity.yml
@@ -0,0 +1,19 @@
+Bankiru\Api\JsonRpc\Test\Entity\SampleEntity:
+ exclusion_policy: ALL
+ properties:
+ id:
+ type: integer
+ serialized_name: id
+ expose: true
+
+ payload:
+ type: string
+ serialized_name: sample_payload
+ expose: true
+
+ secret:
+ type: string
+ serialized_name: private_payload
+ groups: [private]
+ since_version: 0.1
+ expose: true
diff --git a/Test/Tests/AnnotatedControllerTest.php b/Test/Tests/AnnotatedControllerTest.php
index 74691c5..95dc5f0 100644
--- a/Test/Tests/AnnotatedControllerTest.php
+++ b/Test/Tests/AnnotatedControllerTest.php
@@ -2,12 +2,10 @@
namespace Bankiru\Api\JsonRpc\Test\Tests;
-use Bankiru\Api\JsonRpc\JsonRpcBundle;
+use Bankiru\Api\JsonRpc\BankiruJsonRpcServerBundle;
use ScayTrase\Api\JsonRpc\SyncResponse;
-use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
-class AnnotatedControllerTest extends JsonRpcTestCase
+final class AnnotatedControllerTest extends JsonRpcTestCase
{
public function testNestedContext()
{
@@ -16,7 +14,7 @@ public function testNestedContext()
$client,
'/test/private/',
[
- 'jsonrpc' => JsonRpcBundle::VERSION,
+ 'jsonrpc' => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
'method' => 'prefix/annotation/sub',
'id' => 'test',
'params' => [
@@ -30,16 +28,16 @@ public function testNestedContext()
self::assertInstanceOf(\stdClass::class, $content);
$jsonResponse = new SyncResponse($content);
- self::assertTrue($jsonResponse->isSuccessful());
+ self::assertTrue($jsonResponse->isSuccessful(), json_encode($content, JSON_PRETTY_PRINT));
}
/**
* @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
- * @expectedExceptionMessage Not an valid JSON request
+ * @expectedExceptionMessage Not a valid JSON-RPC request
*/
public function testEmptyRequest()
{
- $client = self::createClient();
+ $client = self::createClient();
$this->sendRequest(
$client,
'/test/private/',
diff --git a/Test/Tests/EntityConversionTest.php b/Test/Tests/EntityConversionTest.php
index 9174500..952a11d 100644
--- a/Test/Tests/EntityConversionTest.php
+++ b/Test/Tests/EntityConversionTest.php
@@ -2,10 +2,10 @@
namespace Bankiru\Api\JsonRpc\Test\Tests;
-use Bankiru\Api\JsonRpc\JsonRpcBundle;
+use Bankiru\Api\JsonRpc\BankiruJsonRpcServerBundle;
use ScayTrase\Api\JsonRpc\SyncResponse;
-class EntityConversionTest extends JsonRpcTestCase
+final class EntityConversionTest extends JsonRpcTestCase
{
public function testEntitySerialization()
{
@@ -13,7 +13,7 @@ public function testEntitySerialization()
self::createClient(),
'/test/',
[
- 'jsonrpc' => JsonRpcBundle::VERSION,
+ 'jsonrpc' => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
'method' => 'entity',
'id' => 'test',
'params' => [
@@ -28,10 +28,13 @@ public function testEntitySerialization()
$jsonResponse = new SyncResponse($content);
self::assertTrue($jsonResponse->isSuccessful(), json_encode($content, JSON_PRETTY_PRINT));
- self::assertTrue(isset($jsonResponse->getBody()->{'sample_payload'}));
+ self::assertTrue(isset($jsonResponse->getBody()->{'sample_payload'}), json_encode($content, JSON_PRETTY_PRINT));
self::assertEquals('my-payload', $jsonResponse->getBody()->{'sample_payload'});
- self::assertFalse(isset($jsonResponse->getBody()->{'private_payload'}));
+ self::assertFalse(
+ isset($jsonResponse->getBody()->{'private_payload'}),
+ json_encode($content, JSON_PRETTY_PRINT)
+ );
}
public function testPrivateEntityFields()
@@ -40,7 +43,7 @@ public function testPrivateEntityFields()
self::createClient(),
'/test/private/',
[
- 'jsonrpc' => JsonRpcBundle::VERSION,
+ 'jsonrpc' => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
'method' => 'entity/private',
'id' => 'test',
'params' => [
@@ -54,17 +57,26 @@ public function testPrivateEntityFields()
self::assertInstanceOf(\stdClass::class, $content);
$jsonResponse = new SyncResponse($content);
- self::assertTrue($jsonResponse->isSuccessful());
- self::assertTrue(isset($jsonResponse->getBody()->{'sample_payload'}));
- self::assertEquals('my-payload', $jsonResponse->getBody()->{'sample_payload'});
-
- self::assertTrue(
- isset($jsonResponse->getBody()->{'private_payload'}),
+ self::assertTrue($jsonResponse->isSuccessful(), json_encode($content, JSON_PRETTY_PRINT));
+ self::assertTrue(isset($jsonResponse->getBody()->{'sample_payload'}), json_encode($content, JSON_PRETTY_PRINT));
+ self::assertEquals(
+ 'my-payload',
+ $jsonResponse->getBody()->{'sample_payload'},
json_encode($content, JSON_PRETTY_PRINT)
);
- self::assertEquals('secret-payload', $jsonResponse->getBody()->{'private_payload'});
- }
+ if (static::$kernel->getContainer()->has('jms_serializer')) {
+ self::assertTrue(
+ isset($jsonResponse->getBody()->{'private_payload'}),
+ json_encode($content, JSON_PRETTY_PRINT)
+ );
+ self::assertEquals(
+ 'secret-payload',
+ $jsonResponse->getBody()->{'private_payload'},
+ json_encode($content, JSON_PRETTY_PRINT)
+ );
+ }
+ }
public function testNestedContext()
{
@@ -72,7 +84,7 @@ public function testNestedContext()
self::createClient(),
'/test/private/',
[
- 'jsonrpc' => JsonRpcBundle::VERSION,
+ 'jsonrpc' => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
'method' => 'entity/nested',
'id' => 'test',
'params' => [
@@ -86,14 +98,24 @@ public function testNestedContext()
self::assertInstanceOf(\stdClass::class, $content);
$jsonResponse = new SyncResponse($content);
- self::assertTrue($jsonResponse->isSuccessful());
- self::assertTrue(isset($jsonResponse->getBody()->{'sample_payload'}));
- self::assertEquals('my-payload', $jsonResponse->getBody()->{'sample_payload'});
-
- self::assertTrue(
- isset($jsonResponse->getBody()->{'private_payload'}),
+ self::assertTrue($jsonResponse->isSuccessful(), json_encode($content, JSON_PRETTY_PRINT));
+ self::assertTrue(isset($jsonResponse->getBody()->{'sample_payload'}), json_encode($content, JSON_PRETTY_PRINT));
+ self::assertEquals(
+ 'my-payload',
+ $jsonResponse->getBody()->{'sample_payload'},
json_encode($content, JSON_PRETTY_PRINT)
);
- self::assertEquals('secret-payload', $jsonResponse->getBody()->{'private_payload'});
+
+ if (static::$kernel->getContainer()->has('jms_serializer')) {
+ self::assertTrue(
+ isset($jsonResponse->getBody()->{'private_payload'}),
+ json_encode($content, JSON_PRETTY_PRINT)
+ );
+ self::assertEquals(
+ 'secret-payload',
+ $jsonResponse->getBody()->{'private_payload'},
+ json_encode($content, JSON_PRETTY_PRINT)
+ );
+ }
}
}
diff --git a/Test/Tests/ExceptionHandlingTest.php b/Test/Tests/ExceptionHandlingTest.php
index a789512..f64984e 100644
--- a/Test/Tests/ExceptionHandlingTest.php
+++ b/Test/Tests/ExceptionHandlingTest.php
@@ -2,12 +2,12 @@
namespace Bankiru\Api\JsonRpc\Test\Tests;
-use Bankiru\Api\JsonRpc\JsonRpcBundle;
+use Bankiru\Api\JsonRpc\BankiruJsonRpcServerBundle;
use ScayTrase\Api\JsonRpc\JsonRpcError;
use ScayTrase\Api\JsonRpc\JsonRpcResponseInterface;
use ScayTrase\Api\JsonRpc\SyncResponse;
-class ExceptionHandlingTest extends JsonRpcTestCase
+final class ExceptionHandlingTest extends JsonRpcTestCase
{
public function testBatchWithFailingMethod()
{
@@ -18,7 +18,7 @@ public function testBatchWithFailingMethod()
'/test/',
[
[
- 'jsonrpc' => JsonRpcBundle::VERSION,
+ 'jsonrpc' => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
'method' => 'sample',
'id' => 'test',
'params' => [
@@ -27,7 +27,7 @@ public function testBatchWithFailingMethod()
],
],
[
- 'jsonrpc' => JsonRpcBundle::VERSION,
+ 'jsonrpc' => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
'method' => 'exception',
'id' => 'test2',
'params' => [
@@ -37,7 +37,7 @@ public function testBatchWithFailingMethod()
],
[
//notification - no id
- 'jsonrpc' => JsonRpcBundle::VERSION,
+ 'jsonrpc' => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
'method' => 'notification',
'param' => [
'notification' => 'message',
@@ -68,7 +68,7 @@ public function getInvalidRequests()
return [
'No method' => [
[
- 'jsonrpc' => JsonRpcBundle::VERSION,
+ 'jsonrpc' => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
'id' => 'test',
'params' => [],
],
diff --git a/Test/Tests/Fixtures/Kernel.php b/Test/Tests/Fixtures/Kernel.php
deleted file mode 100644
index 53a93f6..0000000
--- a/Test/Tests/Fixtures/Kernel.php
+++ /dev/null
@@ -1,47 +0,0 @@
-load(__DIR__ . '/config.yml');
- }
-
- public function getEnvironment()
- {
- return 'test';
- }
-}
diff --git a/Test/Tests/Fixtures/config.yml b/Test/Tests/Fixtures/config.yml
deleted file mode 100644
index fe38e1e..0000000
--- a/Test/Tests/Fixtures/config.yml
+++ /dev/null
@@ -1,12 +0,0 @@
-framework:
- test: ~
- secret: test
- assets: false
- router:
- resource: "%kernel.root_dir%/routing.yml"
- templating: false
- translator: ~
-
-services:
- logger:
- class: Psr\Log\NullLogger
diff --git a/Test/Tests/JsonRpcTestCase.php b/Test/Tests/JsonRpcTestCase.php
index db78b78..400c18e 100644
--- a/Test/Tests/JsonRpcTestCase.php
+++ b/Test/Tests/JsonRpcTestCase.php
@@ -2,7 +2,11 @@
namespace Bankiru\Api\JsonRpc\Test\Tests;
-use Bankiru\Api\JsonRpc\Test\Tests\Fixtures\Kernel;
+use Bankiru\Api\BrowserKit\JsonRpcClient;
+use Bankiru\Api\JsonRpc\Test\Kernel\TestKernel;
+use ScayTrase\Api\IdGenerator\UuidGenerator;
+use ScayTrase\Api\JsonRpc\JsonRpcResponseInterface;
+use ScayTrase\Api\Rpc\RpcRequestInterface;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpKernel\Client;
@@ -10,7 +14,7 @@ abstract class JsonRpcTestCase extends WebTestCase
{
protected static function getKernelClass()
{
- return Kernel::class;
+ return TestKernel::class;
}
/**
@@ -30,4 +34,22 @@ protected function sendRequest(Client $client = null, $endpoint, $requests)
return $client->getResponse();
}
+
+ /**
+ * @param RpcRequestInterface $request
+ * @param string $endpoint
+ * @param Client|null $client
+ *
+ * @return JsonRpcResponseInterface
+ */
+ protected function sendJsonRpcRequest(RpcRequestInterface $request, $endpoint, Client $client = null)
+ {
+ if (null === $client) {
+ $client = static::createClient();
+ }
+
+ $jsonRpcClient = new JsonRpcClient($client, $endpoint, new UuidGenerator());
+
+ return $jsonRpcClient->invoke($request)->getResponse($request);
+ }
}
diff --git a/Test/Tests/RouterTest.php b/Test/Tests/RouterTest.php
index f511a86..4c56bab 100644
--- a/Test/Tests/RouterTest.php
+++ b/Test/Tests/RouterTest.php
@@ -7,7 +7,7 @@
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Routing\RequestContext;
-class RouterTest extends WebTestCase
+final class RouterTest extends WebTestCase
{
public function testHttpRoutes()
{
@@ -16,18 +16,18 @@ public function testHttpRoutes()
$context = new RequestContext();
$context->setMethod('POST');
$router->setContext($context);
- $router->match('/test/');
+ self::assertNotEmpty($router->match('/test/'));
}
public function testRpcRouterCollection()
{
$client = self::createClient();
- foreach (['test', 'test_private'] as $endpoint) /** @var MethodCollection $collection */ {
+ foreach (['test', 'test_private'] as $endpoint) {
/** @var Router $router */
- $router = $client->getContainer()->get('rpc.endpoint_router.' . $endpoint);
+ $router = $client->getContainer()->get('rpc_server.endpoint_router.' . $endpoint);
self::assertNotNull($router);
- $collection = $router->getCollection();
+ $collection = $router->getMethodCollection();
self::assertNotNull($router);
self::assertInstanceOf(MethodCollection::class, $collection);
diff --git a/Test/Tests/SampleControllerTest.php b/Test/Tests/SampleControllerTest.php
index 54ca6e1..9163f9c 100644
--- a/Test/Tests/SampleControllerTest.php
+++ b/Test/Tests/SampleControllerTest.php
@@ -2,10 +2,10 @@
namespace Bankiru\Api\JsonRpc\Test\Tests;
-use Bankiru\Api\JsonRpc\JsonRpcBundle;
+use Bankiru\Api\JsonRpc\BankiruJsonRpcServerBundle;
use ScayTrase\Api\JsonRpc\SyncResponse;
-class SampleControllerTest extends JsonRpcTestCase
+final class SampleControllerTest extends JsonRpcTestCase
{
public function testBatchRequest()
{
@@ -14,19 +14,19 @@ public function testBatchRequest()
'/test/',
[
[
- 'jsonrpc' => JsonRpcBundle::VERSION,
- 'method' => 'sample',
- 'id' => 'test',
- 'params' => [
+ 'jsonrpc' => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
+ 'method' => 'sample',
+ 'id' => 'test',
+ 'params' => [
'param1' => 'value1',
'param2' => 100500,
],
],
[
//notification - no id
- 'jsonrpc' => JsonRpcBundle::VERSION,
- 'method' => 'notification',
- 'param' => [
+ 'jsonrpc' => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
+ 'method' => 'notification',
+ 'param' => [
'notification' => 'message',
],
],
@@ -42,10 +42,10 @@ public function testArrayRequest()
self::createClient(),
'/test/',
[
- 'jsonrpc' => JsonRpcBundle::VERSION,
- 'method' => 'array',
- 'id' => 'test',
- 'params' => [
+ 'jsonrpc' => BankiruJsonRpcServerBundle::JSONRPC_VERSION,
+ 'method' => 'array',
+ 'id' => 'test',
+ 'params' => [
'payload' => 'my-payload',
],
]
@@ -57,7 +57,14 @@ public function testArrayRequest()
$jsonResponse = new SyncResponse($content);
self::assertTrue($jsonResponse->isSuccessful(), json_encode($content));
- self::assertTrue(isset($jsonResponse->getBody()[0]->{'sample_payload'}));
- self::assertEquals('my-payload', $jsonResponse->getBody()[0]->{'sample_payload'});
+ self::assertTrue(
+ isset($jsonResponse->getBody()[0]->{'sample_payload'}),
+ json_encode($content, JSON_PRETTY_PRINT)
+ );
+ self::assertEquals(
+ 'my-payload',
+ $jsonResponse->getBody()[0]->{'sample_payload'},
+ json_encode($content, JSON_PRETTY_PRINT)
+ );
}
}
diff --git a/Test/Tests/SecurityTest.php b/Test/Tests/SecurityTest.php
new file mode 100644
index 0000000..3e854e2
--- /dev/null
+++ b/Test/Tests/SecurityTest.php
@@ -0,0 +1,24 @@
+sendJsonRpcRequest(new Request('prefix/security/private', []), '/test/');
+
+ self::assertFalse($response->isSuccessful());
+ self::assertEquals($response->getError()->getCode(), JsonRpcError::METHOD_NOT_FOUND);
+ }
+
+ public function testPublicMethodRequest()
+ {
+ $response = $this->sendJsonRpcRequest(new Request('prefix/security/public', []), '/test/');
+
+ self::assertTrue($response->isSuccessful(), json_encode($response, JSON_PRETTY_PRINT));
+ }
+}
diff --git a/Tests/JsonRpcControllerTest.php b/Tests/JsonRpcControllerTest.php
new file mode 100644
index 0000000..76a8401
--- /dev/null
+++ b/Tests/JsonRpcControllerTest.php
@@ -0,0 +1,241 @@
+ [null],
+ 'string' => ['test'],
+ 'invalid_json' => [substr(json_encode(['test']), 2)],
+ ];
+ }
+
+ /**
+ * @dataProvider getInvalidJsonRequests
+ * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException
+ *
+ * @param $content
+ */
+ public function testInvalidJsonHandling($content)
+ {
+ $controller = $this->createController();
+
+ $request = $this->createJsonRequest('/', $content);
+ $controller->jsonRpcAction($request);
+ }
+
+ public function getInvalidJsonRpcRequests()
+ {
+ return [
+ 'invalid version' => [['jsonrpc' => '1.0']],
+ 'no method' => [['jsonrpc' => '2.0']],
+ 'no version' => [['method' => 'test']],
+ ];
+ }
+
+ /**
+ * @dataProvider getInvalidJsonRpcRequests
+ * @expectedException \Bankiru\Api\JsonRpc\Exception\InvalidRequestException
+ *
+ * @param $content
+ */
+ public function testInvalidJsonRpcHandling($content)
+ {
+ $controller = $this->createController();
+
+ $request = $this->createJsonRequest('/', $content);
+ $controller->jsonRpcAction($request);
+ }
+
+ public function getValidResponseAndRequests()
+ {
+ return [
+ 'empty batch' => [[], '[]'],
+ 'single' => [
+ [
+ 'jsonrpc' => '2.0',
+ 'id' => 'test',
+ 'method' => 'test',
+ ],
+ '{"jsonrpc":"2.0","id":"test","result":{"success":true}}',
+ ],
+ 'batch' => [
+ [
+ [
+ 'jsonrpc' => '2.0',
+ 'id' => 'test',
+ 'method' => 'test',
+ ],
+ ],
+ '[{"jsonrpc":"2.0","id":"test","result":{"success":true}}]',
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider getValidResponseAndRequests
+ *
+ * @param array $content
+ * @param string $responseBody
+ */
+ public function testValidRequestHandling($content, $responseBody)
+ {
+ $controller = $this->createController();
+ $request = $this->createJsonRequest(
+ '/',
+ $content
+ );
+ $response = $controller->jsonRpcAction($request);
+
+ self::assertInstanceOf(JsonRpcHttpResponse::class, $response);
+ self::assertTrue($response->isSuccessful());
+ self::assertEquals($responseBody, $response->getContent());
+ }
+
+ public function testExceptionHandling()
+ {
+ $controller = $this->createController();
+ $request = $this->createJsonRequest(
+ '/',
+ [
+ 'jsonrpc' => '2.0',
+ 'id' => 'test',
+ 'method' => 'exception',
+ ]
+ );
+ $response = $controller->jsonRpcAction($request);
+
+ self::assertTrue($response->isSuccessful());
+ self::assertEquals(
+ '{"jsonrpc":"2.0","id":"test","error":{"code":-32603,"message":"Failure!","data":null}}',
+ $response->getContent()
+ );
+ }
+
+ public function testExceptionHandlingAmongBatchRequest()
+ {
+ $controller = $this->createController();
+ $request = $this->createJsonRequest(
+ '/',
+ [
+ [
+ 'jsonrpc' => '2.0',
+ 'id' => 'test1',
+ 'method' => 'test',
+ ],
+ [
+ 'jsonrpc' => '2.0',
+ 'id' => 'test2',
+ 'method' => 'exception',
+ ],
+ ]
+ );
+ $response = $controller->jsonRpcAction($request);
+
+ self::assertTrue($response->isSuccessful());
+ self::assertEquals(
+ '[{"jsonrpc":"2.0","id":"test1","result":{"success":true}},{"jsonrpc":"2.0","id":"test2","error":{"code":-32603,"message":"Failure!","data":null}}]',
+ $response->getContent()
+ );
+ }
+
+ /**
+ * @param string $uri
+ * @param mixed $content
+ *
+ * @return Request
+ */
+ private function createJsonRequest($uri, $content)
+ {
+ return Request::create($uri, 'POST', [], [], [], [], json_encode($content));
+ }
+
+ private function getContainerMock()
+ {
+ $mock = $this->prophesize(ContainerInterface::class);
+ $kernel = $this->prophesize(KernelInterface::class);
+ $resolver = $this->prophesize(ControllerResolverInterface::class);
+ $resolver->getController(Argument::type(RpcRequestInterface::class))->willReturn(
+ function (JsonRpcRequestInterface $request) {
+ if ($request->getMethod() === 'exception') {
+ throw new \LogicException('Failure!');
+ }
+
+ return new JsonRpcResponse($request->getId(), (object)['success' => true]);
+ }
+ );
+ $resolver->getArguments(Argument::type(RpcRequestInterface::class), Argument::any())->will(
+ function (array $args) {
+ return [
+ $args[0],
+ ];
+ }
+ );
+
+ $evm = $this->prophesize(EventDispatcherInterface::class);
+ $evm->dispatch(Argument::exact(RpcEvents::EXCEPTION), Argument::type(GetExceptionResponseEvent::class))
+ ->will(
+ function ($args) {
+ /** @var GetExceptionResponseEvent $event */
+ $event = $args[1];
+
+ /** @var JsonRpcRequestInterface $request */
+ $request = $event->getRequest();
+
+ $event->setResponse(
+ new JsonRpcResponse(
+ $request->getId(),
+ null, new JsonRpcError(
+ JsonRpcError::INTERNAL_ERROR,
+ $event->getException()->getMessage()
+ )
+ )
+ );
+ }
+ );
+ $evm->dispatch(Argument::exact(RpcEvents::FINISH_REQUEST), Argument::type(FinishRequestEvent::class))
+ ->willReturn(null);
+ $evm->dispatch(Argument::exact(RpcEvents::CONTROLLER), Argument::type(FilterControllerEvent::class))
+ ->willReturn(null);
+ $evm->dispatch(Argument::exact(RpcEvents::REQUEST), Argument::type(GetResponseEvent::class))->willReturn(null);
+ $evm->dispatch(Argument::exact(RpcEvents::RESPONSE), Argument::type(FilterResponseEvent::class))
+ ->willReturn(null);
+
+ $mock->get(Argument::exact('jsonrpc_server.controller_resolver'))->willReturn($resolver->reveal());
+ $mock->get(Argument::exact('event_dispatcher'))->willReturn($evm->reveal());
+ $mock->get(Argument::exact('kernel'))->willReturn($kernel->reveal());
+
+ return $mock->reveal();
+ }
+
+ private function createController()
+ {
+ $controller = new JsonRpcController();
+ $controller->setContainer($this->getContainerMock());
+
+ return $controller;
+ }
+}
diff --git a/Tests/JsonRpcHttpResponseTest.php b/Tests/JsonRpcHttpResponseTest.php
new file mode 100644
index 0000000..dad36f4
--- /dev/null
+++ b/Tests/JsonRpcHttpResponseTest.php
@@ -0,0 +1,43 @@
+ true], null);
+
+ $error = new JsonRpcResponse(
+ 'single',
+ null,
+ new JsonRpcError(JsonRpcError::METHOD_NOT_FOUND, 'Invalid method')
+ );
+
+ return [
+ 'empty' => [null],
+ 'empty array' => [[]],
+ 'single success' => [clone $success],
+ 'single failure' => [clone $error],
+ 'mixed array' => [[clone $success, clone $error]],
+ ];
+ }
+
+ /**
+ * @dataProvider getResponseVariants
+ *
+ * @param $responses
+ */
+ public function testResponseProvidesCorrectHeaders($responses)
+ {
+ $response = new JsonRpcHttpResponse($responses);
+ self::assertTrue($response->isSuccessful());
+ self::assertTrue($response->headers->has('Content-Type'));
+ self::assertEquals('application/json', $response->headers->get('Content-Type'));
+ }
+}
diff --git a/bootstrap.php b/bootstrap.php
index 8c57a77..445fa3b 100644
--- a/bootstrap.php
+++ b/bootstrap.php
@@ -1,12 +1,12 @@
dump(new Configuration());
+
+
diff --git a/phpunit.xml b/phpunit.xml
index 3b8fa98..31ec208 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -9,17 +9,21 @@
>
-
-
+
./Test/Tests/
+
+ ./Tests/
+
+ Test/
+ Tests/
vendor/
build/