diff --git a/.gitignore b/.gitignore index e17ee95..216c574 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /composer.lock /build /var +/cache \ No newline at end of file diff --git a/Controller/GraphqliteController.php b/Controller/GraphqliteController.php new file mode 100644 index 0000000..39f9e09 --- /dev/null +++ b/Controller/GraphqliteController.php @@ -0,0 +1,105 @@ +standardServer = $standardServer; + $this->httpMessageFactory = $httpMessageFactory ?: new DiactorosFactory(); + $this->debug = $debug ?? false; + } + + public function loadRoutes(): RouteCollection + { + $routes = new RouteCollection(); + + // prepare a new route + $path = '/graphql'; + $defaults = [ + '_controller' => self::class.'::handleRequest', + ]; + $route = new Route($path, $defaults); + + // add the new route to the route collection + $routeName = 'graphqliteRoute'; + $routes->add($routeName, $route); + + return $routes; + } + + public function handleRequest(Request $request): Response + { + $psr7Request = $this->httpMessageFactory->createRequest($request); + + if (strtoupper($request->getMethod()) === "POST" && empty($psr7Request->getParsedBody())) { + $content = $psr7Request->getBody()->getContents(); + $parsedBody = json_decode($content, true); + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \RuntimeException('Invalid JSON received in POST body: '.json_last_error_msg()); + } + $psr7Request = $psr7Request->withParsedBody($parsedBody); + } + + // Let's parse the request and adapt it for file uploads. + $uploadMiddleware = new UploadMiddleware(); + $psr7Request = $uploadMiddleware->processRequest($psr7Request); + + $result = $this->handlePsr7Request($psr7Request); + + return new JsonResponse($result); + } + + private function handlePsr7Request(ServerRequestInterface $request): array + { + $result = $this->standardServer->executePsrRequest($request); + + if ($result instanceof ExecutionResult) { + return $result->toArray($this->debug); + } + if (is_array($result)) { + return array_map(function (ExecutionResult $executionResult) { + return $executionResult->toArray($this->debug); + }, $result); + } + if ($result instanceof Promise) { + throw new RuntimeException('Only SyncPromiseAdapter is supported'); + } + throw new RuntimeException('Unexpected response from StandardServer::executePsrRequest'); // @codeCoverageIgnore + } +} diff --git a/EventListeners/RequestHandler.php b/EventListeners/RequestHandler.php deleted file mode 100644 index 743629b..0000000 --- a/EventListeners/RequestHandler.php +++ /dev/null @@ -1,157 +0,0 @@ -standardServer = $standardServer; - $this->httpMessageFactory = $httpMessageFactory ?: new DiactorosFactory(); - $this->graphqlUri = $graphqlUri; - $this->debug = $debug === null ? false : $debug; - } - - /** - * {@inheritdoc} - */ - public static function getSubscribedEvents() - { - $events[KernelEvents::REQUEST][] = array('handleRequest', 33); - return $events; - } - - public function handleRequest(GetResponseEvent $event) - { - // Let's only handle the main request (the event might be triggered for sub-requests for error displaying for instance) - if ($event->getRequestType() !== HttpKernelInterface::MASTER_REQUEST) { - return; - } - - $request = $event->getRequest(); - - if (!$this->isGraphqlRequest($request)) { - return; - } - - $psr7Request = $this->httpMessageFactory->createRequest($request); - - if (strtoupper($request->getMethod()) == "POST" && empty($psr7Request->getParsedBody())) { - $content = $psr7Request->getBody()->getContents(); - $parsedBody = json_decode($content, true); - if (json_last_error() !== JSON_ERROR_NONE) { - throw new \RuntimeException('Invalid JSON received in POST body: '.json_last_error_msg()); - } - $psr7Request = $psr7Request->withParsedBody($parsedBody); - } - - // Let's parse the request and adapt it for file uploads. - $uploadMiddleware = new UploadMiddleware(); - $psr7Request = $uploadMiddleware->processRequest($psr7Request); - - - // Hack for Graph - /*if (strtoupper($request->getMethod()) == "GET") { - $params = $request->getQueryParams(); - $params["variables"] = $params["variables"] === 'undefined' ? null : $params["variables"]; - $request = $request->withQueryParams($params); - } else { - $params = $request->getParsedBody(); - $params["variables"] = $params["variables"] === 'undefined' ? null : $params["variables"]; - $request = $request->withParsedBody($params); - }*/ - - $result = $this->handlePsr7Request($psr7Request); - - $response = new JsonResponse($result); - $event->setResponse($response); - } - - private function handlePsr7Request(ServerRequestInterface $request): array - { - $result = $this->standardServer->executePsrRequest($request); - - if ($result instanceof ExecutionResult) { - return $result->toArray($this->debug); - } - if (is_array($result)) { - return array_map(function (ExecutionResult $executionResult) { - return $executionResult->toArray($this->debug); - }, $result); - } - if ($result instanceof Promise) { - throw new RuntimeException('Only SyncPromiseAdapter is supported'); - } - throw new RuntimeException('Unexpected response from StandardServer::executePsrRequest'); // @codeCoverageIgnore - } - - private function isGraphqlRequest(Request $request) : bool - { - return $this->isMethodAllowed($request) && ($this->hasUri($request) || $this->hasGraphqlHeader($request)); - } - private function isMethodAllowed(Request $request) : bool - { - return in_array($request->getMethod(), $this->allowedMethods, true); - } - private function hasUri(Request $request) : bool - { - return $this->graphqlUri === $request->getPathInfo(); - } - private function hasGraphqlHeader(Request $request) : bool - { - if (! $request->headers->has('content-type')) { - return false; - } - - $requestHeaderList = $request->headers->get('content-type', null, false); - if ($requestHeaderList === null) { - return false; - } - foreach ($this->graphqlHeaderList as $allowedHeader) { - if (in_array($allowedHeader, $requestHeaderList, true)) { - return true; - } - } - return false; - } -} diff --git a/Resources/config/container/graphqlite.xml b/Resources/config/container/graphqlite.xml index 52121e3..83b2287 100644 --- a/Resources/config/container/graphqlite.xml +++ b/Resources/config/container/graphqlite.xml @@ -61,10 +61,6 @@ - - - - @@ -101,6 +97,8 @@ + + \ No newline at end of file diff --git a/Resources/config/routes.xml b/Resources/config/routes.xml new file mode 100644 index 0000000..171d2b7 --- /dev/null +++ b/Resources/config/routes.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/Tests/GraphqliteTestingKernel.php b/Tests/GraphqliteTestingKernel.php index 80c6df9..1a73640 100644 --- a/Tests/GraphqliteTestingKernel.php +++ b/Tests/GraphqliteTestingKernel.php @@ -4,16 +4,24 @@ namespace TheCodingMachine\Graphqlite\Bundle\Tests; +use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\HttpKernel\Kernel; +use Symfony\Component\Routing\RouteCollectionBuilder; use TheCodingMachine\Graphqlite\Bundle\GraphqliteBundle; class GraphqliteTestingKernel extends Kernel { + use MicroKernelTrait; const CONFIG_EXTS = '.{php,xml,yaml,yml}'; + public function __construct() + { + parent::__construct('test', true); + } + public function registerBundles() { return [ @@ -22,7 +30,7 @@ public function registerBundles() ]; } - public function registerContainerConfiguration(LoaderInterface $loader) + public function configureContainer(ContainerBuilder $c, LoaderInterface $loader) { $loader->load(function(ContainerBuilder $container) { $container->loadFromExtension('framework', array( @@ -42,4 +50,14 @@ public function registerContainerConfiguration(LoaderInterface $loader) $loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob'); $loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob'); } + + protected function configureRoutes(RouteCollectionBuilder $routes) + { + $routes->import(__DIR__.'/../Resources/config/routes.xml'); + } + + public function getCacheDir() + { + return __DIR__.'/../cache/'.spl_object_hash($this); + } } diff --git a/composer.json b/composer.json index 1445b21..9beff90 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ "beberlei/porpaginas": "^1.2" }, "scripts": { - "phpstan": "phpstan analyse GraphqliteBundle.php DependencyInjection/ EventListeners/ Mappers/ Resources/ Security/ -c phpstan.neon --level=7 --no-progress" + "phpstan": "phpstan analyse GraphqliteBundle.php DependencyInjection/ Controller/ Mappers/ Resources/ Security/ -c phpstan.neon --level=7 --no-progress" }, "suggest": { "symfony/security-bundle": "To use @Logged or @Right annotations" diff --git a/phpstan.neon b/phpstan.neon index 1cd87eb..9481751 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,7 +1,6 @@ parameters: ignoreErrors: - "#Call to an undefined method Symfony\\\\Component\\\\Config\\\\Definition\\\\Builder\\\\NodeDefinition::children\\(\\)#" - - "/Parameter #2 $haystack of function in_array expects array, array|string given./" - "#Access to an undefined property GraphQL\\\\Type\\\\Definition\\\\NamedType&GraphQL\\\\Type\\\\Definition\\\\OutputType::\\$name.#" #includes: # - vendor/thecodingmachine/phpstan-strict-rules/phpstan-strict-rules.neon \ No newline at end of file