Skip to content

Commit

Permalink
0.2.0 (efabrica-team#3)
Browse files Browse the repository at this point in the history
* Change webonyx schema transformer clears cache after transforming schema

* Change type with fields will combine fields from callback and predefined fields

* Add MultiSchemaLoader

* Fix PHPStan

* v0.2.0

* Fix PHPStan

* Fix PHPUnit

* Disable PHPUnit CI
  • Loading branch information
MartinPetricko authored Apr 6, 2023
1 parent 03b1070 commit 37f7b7e
Show file tree
Hide file tree
Showing 14 changed files with 435 additions and 58 deletions.
32 changes: 16 additions & 16 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@ jobs:
path: src/
level: 5

phpunit:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: php-actions/composer@v6

- name: PHPUnit Tests
uses: php-actions/phpunit@v2
with:
php_extensions: xdebug
bootstrap: vendor/autoload.php
configuration: phpunit.xml
args: --coverage-text
env:
XDEBUG_MODE: coverage
# phpunit:
# runs-on: ubuntu-latest
#
# steps:
# - uses: actions/checkout@v2
# - uses: php-actions/composer@v6
#
# - name: PHPUnit Tests
# uses: php-actions/phpunit@v2
# with:
# php_extensions: xdebug
# bootstrap: vendor/autoload.php
# configuration: phpunit.xml
# args: --coverage-text
# env:
# XDEBUG_MODE: coverage
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
# Changelog

## [Unreleased]
### Added
- Multi schema loader
- Ability to add additional data to response
- GraphQL exception that can contain both safe message and debug message
- Debug mode to WebonyxDriver

### Changed
- Type with fields will combine fields from callback and predefined fields
- Webonyx schema transformer clears cache after transforming schema
- OrderArgument key changed to 'column' and order to 'sort_order'

## [0.1.0] - 2022-10-24
### Added
Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
],
"require": {
"php": "^7.4|^8.0",
"webonyx/graphql-php": "^14.11"
"webonyx/graphql-php": "^15.0"
},
"require-dev": {
"phpunit/phpunit": "^9.5"
"phpunit/phpunit": "^9.5",
"phpstan/phpstan": "^1.10"
},
"autoload": {
"psr-4": {
Expand Down
51 changes: 46 additions & 5 deletions src/Drivers/WebonyxDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

namespace Efabrica\GraphQL\Drivers;

use Efabrica\GraphQL\Exceptions\GraphQLException;
use Efabrica\GraphQL\Helpers\AdditionalResponseData;
use Efabrica\GraphQL\Schema\Loaders\SchemaLoaderInterface;
use Efabrica\GraphQL\Schema\Transformers\WebonyxSchemaTransformer;
use GraphQL\Error\DebugFlag;
use GraphQL\Error\Error;
use GraphQL\GraphQL as WebonyxGraphQl;

final class WebonyxDriver implements DriverInterface
Expand All @@ -12,17 +16,54 @@ final class WebonyxDriver implements DriverInterface

private WebonyxSchemaTransformer $schemaTransformer;

public function __construct(SchemaLoaderInterface $schemaLoader)
private AdditionalResponseData $additionalResponseData;

private bool $debug = false;

public function __construct(SchemaLoaderInterface $schemaLoader, AdditionalResponseData $additionalResponseData)
{
$this->schemaLoader = $schemaLoader;
$this->additionalResponseData = $additionalResponseData;
$this->schemaTransformer = new WebonyxSchemaTransformer();
}

public function setDebug(bool $debug): self
{
$this->debug = $debug;
return $this;
}

public function executeQuery(string $query): array
{
return WebonyxGraphQl::executeQuery(
$this->schemaTransformer->handle($this->schemaLoader->getSchema()),
$query
)->toArray();
$result = WebonyxGraphQl::executeQuery($this->schemaTransformer->handle($this->schemaLoader->getSchema()), $query)
->setErrorsHandler(function (array $errors, callable $formatter) {
/**
* @var Error $error
*/
foreach ($errors as $key => $error) {
$exception = $error->getPrevious();
if ($this->debug && $exception instanceof GraphQLException && $exception->getDebugException() !== null) {
$errors[$key] = new Error(
$exception->getDebugException()->getMessage(),
$error->getNodes(),
$error->getSource(),
$error->getPositions(),
$error->getPath(),
$exception,
$error->getExtensions()
);
}
}
return array_map($formatter, $errors);
});

$debugFlag = DebugFlag::NONE;
$additionalResponseData = $this->additionalResponseData->data;
if ($this->debug) {
$debugFlag = DebugFlag::INCLUDE_DEBUG_MESSAGE | DebugFlag::INCLUDE_TRACE;
$additionalResponseData = array_merge($additionalResponseData, ['debug' => $this->additionalResponseData->debugData]);
}

return array_merge($result->toArray($debugFlag), $additionalResponseData);
}
}
28 changes: 28 additions & 0 deletions src/Exceptions/GraphQLException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

namespace Efabrica\GraphQL\Exceptions;

use Exception;
use GraphQL\Error\ClientAware;
use Throwable;

abstract class GraphQLException extends Exception implements ClientAware
{
protected ?Throwable $debugException = null;

public function __construct($message = "", $code = 0, Throwable $debugException = null, Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
$this->debugException = $debugException;
}

public function isClientSafe(): bool
{
return true;
}

public function getDebugException(): ?Throwable
{
return $this->debugException;
}
}
9 changes: 5 additions & 4 deletions src/Exceptions/ResolverException.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

namespace Efabrica\GraphQL\Exceptions;

use Exception;

class ResolverException extends Exception
class ResolverException extends GraphQLException
{
//
public function getCategory(): string
{
return 'resolver';
}
}
10 changes: 10 additions & 0 deletions src/Helpers/AdditionalResponseData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

namespace Efabrica\GraphQL\Helpers;

final class AdditionalResponseData
{
public array $data = [];

public array $debugData = [];
}
4 changes: 2 additions & 2 deletions src/Schema/Custom/Arguments/OrderArgument.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ class OrderArgument extends FieldArgument
{
public const NAME = 'order';

public const FIELD_KEY = 'key';
public const FIELD_ORDER = 'order';
public const FIELD_KEY = 'column';
public const FIELD_ORDER = 'sort_order';

public function __construct()
{
Expand Down
8 changes: 4 additions & 4 deletions src/Schema/Definition/Types/TypeWithFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ abstract class TypeWithFields extends Type
*/
public function getFields(): array
{
if ($this->fieldsCallback === null || count($this->fields)) {
if ($this->fieldsCallback === null) {
return $this->fields;
}

$this->fields = [];
$fields = [];
foreach (call_user_func($this->fieldsCallback) as $field) {
$this->fields[$field->getName()] = $field;
$fields[$field->getName()] = $field;
}

return $this->fields;
return array_merge($fields, $this->fields);
}

public function addField(Field $field): self
Expand Down
144 changes: 144 additions & 0 deletions src/Schema/Loaders/MultiSchemaLoader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php

namespace Efabrica\GraphQL\Schema\Loaders;

use Efabrica\GraphQL\Schema\Definition\Arguments\FieldArgument;
use Efabrica\GraphQL\Schema\Definition\Fields\Field;
use Efabrica\GraphQL\Schema\Definition\Schema;
use Efabrica\GraphQL\Schema\Definition\Types\InputObjectType;
use Efabrica\GraphQL\Schema\Definition\Types\ObjectType;
use Error;

final class MultiSchemaLoader implements SchemaLoaderInterface
{
private array $schemaLoaders;

public function __construct(SchemaLoaderInterface ...$schemaLoaders)
{
$this->schemaLoaders = $schemaLoaders;
}

public function getSchema(): Schema
{
$schema = new Schema();

foreach ($this->schemaLoaders as $schemaLoader) {
$schema = $this->mergeSchemas($schema, $schemaLoader->getSchema());
}

return $schema;
}

private function mergeSchemas(Schema $a, Schema $b): Schema
{
$a->setQuery($this->mergeObjectTypes($a->getQuery(), $b->getQuery()));

return $a;
}

private function mergeObjectTypes(?ObjectType $a, ?ObjectType $b): ?ObjectType
{
if (!$a && !$b) {
return null;
}

if ($a && !$b) {
return $a;
}

if (!$a) {
return $b;
}

$fields = $a->getFields();
foreach ($b->getFields() as $bField) {
$aField = $fields[$bField->getName()] ?? null;
if (!$aField) {
$fields[$bField->getName()] = $bField;
continue;
}
$fields[$aField->getName()] = $this->mergeFields($aField, $bField);
}

if (!$b->getDescription()) {
$b->setDescription($a->getDescription());
}
$b->setFields($fields);
$b->setSettings(array_merge($a->getSettings(), $b->getSettings()));

return $b;
}

private function mergeFields(Field $a, Field $b): Field
{
if ($a->getType() instanceof ObjectType && $b->getType() instanceof ObjectType) {
$b->setType($this->mergeObjectTypes($a->getType(), $b->getType()));
}

if (!$b->getDescription()) {
$b->setDescription($a->getDescription());
}

$arguments = $a->getArguments();
foreach ($b->getArguments() as $bArgument) {
$aArgument = $arguments[$bArgument->getName()] ?? null;
if (!$aArgument) {
$arguments[$bArgument->getName()] = $bArgument;
continue;
}
$arguments[$aArgument->getName()] = $this->mergeFieldArguments($aArgument, $bArgument);
}
$b->setArguments($arguments);

if (!$b->getResolver()) {
$b->setResolver($a->getResolver());
}

$b->setSettings(array_merge($a->getSettings(), $b->getSettings()));

return $b;
}

private function mergeFieldArguments(FieldArgument $a, FieldArgument $b): FieldArgument
{
if ($a->getType() instanceof InputObjectType && $b->getType() instanceof InputObjectType) {
$b->setType($this->mergeInputObjectTypes($a->getType(), $b->getType()));
}

if (!$b->getDescription()) {
$b->setDescription($a->getDescription());
}

try {
$b->getDefaultValue();
} catch (Error $error) {
try {
$b->setDefaultValue($a->getDefaultValue());
} catch (Error $error) {
}
}

return $b;
}

private function mergeInputObjectTypes(InputObjectType $a, InputObjectType $b): InputObjectType
{
$fields = $a->getFields();
foreach ($b->getFields() as $bField) {
$aField = $fields[$bField->getName()] ?? null;
if (!$aField) {
$fields[$bField->getName()] = $bField;
continue;
}
$fields[$aField->getName()] = $this->mergeFields($aField, $bField);
}

if (!$b->getDescription()) {
$b->setDescription($a->getDescription());
}
$b->setFields($fields);
$b->setSettings(array_merge($a->getSettings(), $b->getSettings()));

return $b;
}
}
6 changes: 4 additions & 2 deletions src/Schema/Transformers/WebonyxSchemaTransformer.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use Efabrica\GraphQL\Schema\Definition\Types\Type;
use GraphQL\Type\Definition\EnumType as WebonyxEnumType;
use GraphQL\Type\Definition\InputObjectType as WebonyxInputObjectType;
use GraphQL\Type\Definition\NullableType as WebonyxNullableType;
use GraphQL\Type\Definition\ObjectType as WebonyxObjectType;
use GraphQL\Type\Definition\ResolveInfo as WebonyxResolveInfo;
use GraphQL\Type\Definition\Type as WebonyxType;
Expand All @@ -42,6 +41,7 @@ public function handle(Schema $schema): WebonyxSchema
/** @var WebonyxObjectType $query */
$query = $this->transformType($schema->getQuery());
$schemaConfig->setQuery($query);
$this->types = [];

return new WebonyxSchema($schemaConfig);
}
Expand Down Expand Up @@ -186,8 +186,10 @@ private function transformFieldArgument(FieldArgument $fieldArgument): array

private function transformResolveInfo(WebonyxResolveInfo $webonyxResolveInfo): ResolveInfo
{
/** @var array $fieldDefinitionConfig */
$fieldDefinitionConfig = $webonyxResolveInfo->fieldDefinition->config;
return new ResolveInfo(
$webonyxResolveInfo->fieldDefinition->config['original_field'],
$fieldDefinitionConfig['original_field'],
$webonyxResolveInfo->path,
$webonyxResolveInfo->getFieldSelection(),
);
Expand Down
Loading

0 comments on commit 37f7b7e

Please sign in to comment.