Skip to content

Commit

Permalink
Added custom resolver support
Browse files Browse the repository at this point in the history
  • Loading branch information
chillu committed Sep 21, 2016
1 parent 27dad3b commit 5781397
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/Resolver/DataObjectLowerCamelResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace Chillu\GraphQL\Resolver;

use GraphQL\Type\Definition\ResolveInfo;
use SilverStripe\ORM\DataObject;
use SilverStripe\Core\ClassInfo;

/**
* Infer original field name casing from case insensitive database field comparison.
* Useful counterpart to {@link \Convert::upperCamelToLowerCamel()}.
*
* Caution: Assumes fields have been whitelisted through GraphQL type definitions already.
* Does not perform any canView() checks or further validation.
*/
class DataObjectLowerCamelResolver implements IResolver {

public function resolve($object, array $args, $context, ResolveInfo $info)
{
// Correct case for methods (e.g. canView)
if($object->hasMethod($info->fieldName)) {
return $object->{$info->fieldName}();
}

// Correct case (and getters)
if($object->hasField($info->fieldName)) {
return $object->{$info->fieldName};
}

// Infer casing
if($object instanceof DataObject) {
$parents = ClassInfo::ancestry($object, true);
foreach($parents as $parent) {
$fields = DataObject::database_fields($parent);
foreach($fields as $fieldName => $fieldClass) {
if(strcasecmp($fieldName, $info->fieldName) === 0) {
return $object->getField($fieldName);
}
}
}
}
}

}
18 changes: 18 additions & 0 deletions src/Resolver/IResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Chillu\GraphQL\Resolver;

use GraphQL\Type\Definition\ResolveInfo;

interface IResolver {

/**
* @param mixed $object The parent resolved object
* @param array $args Input arguments
* @param mixed $context The context object hat was passed to GraphQL::execute
* @param ResolveInfo $info ResolveInfo object
* @return mixed
*/
public function resolve($object, array $args, $context, ResolveInfo $info);

}
18 changes: 18 additions & 0 deletions src/TypeCreator.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,22 +80,40 @@ public function getAttributes()
);
}

/**
* @param $name
* @param $field
* @return \Closure|null
*/
protected function getFieldResolver($name, $field)
{
$resolveMethod = 'resolve'.ucfirst($name).'Field';
if(isset($field['resolve']))
{
// Preconfigured method
return $field['resolve'];
}
else if(method_exists($this, $resolveMethod))
{
// Method for a particular field
$resolver = array($this, $resolveMethod);
return function() use ($resolver)
{
$args = func_get_args();
return call_user_func_array($resolver, $args);
};
}
else if(method_exists($this, 'resolveField'))
{
// Method for all fields
$resolver = array($this, 'resolveField');
return function() use ($resolver)
{
$args = func_get_args();
// See 'resolveType' on https://github.com/webonyx/graphql-php
return call_user_func_array($resolver, $args);
};
}

return null;
}
Expand Down
19 changes: 19 additions & 0 deletions tests/Fake/DataObjectFake.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Chillu\GraphQL\Tests;

use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;

class DataObjectFake extends DataObject implements TestOnly
{
public function getCustomGetter()
{
return 'customGetterValue';
}

public function customMethod()
{
return 'customMethodValue';
}
}
56 changes: 56 additions & 0 deletions tests/Resolver/DataObjectLowerCamelResolverTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace Chillu\GraphQL\Tests\Resolver;

use Chillu\GraphQL\Resolver\DataObjectLowerCamelResolver;
use Chillu\GraphQL\Tests\DataObjectFake;
use GraphQL\Type\Definition\ResolveInfo;
use SilverStripe\Dev\SapphireTest;

class DataObjectLowerCamelResolverTest extends SapphireTest
{

public function testResolvesOriginalCasing()
{
$fake = new DataObjectFake([
'ID' => 99
]);
$resolver = new DataObjectLowerCamelResolver();
$info = new ResolveInfo([
'fieldName' => 'ID'
]);
$this->assertEquals(99, $resolver->resolve($fake, [], [], $info));
}

public function testResolvesDifferentCasing()
{
$fake = new DataObjectFake([
'ID' => 99
]);
$resolver = new DataObjectLowerCamelResolver();
$info = new ResolveInfo([
'fieldName' => 'id' // lowercase
]);
$this->assertEquals(99, $resolver->resolve($fake, [], [], $info));
}

public function testResolvesCustomGetter()
{
$fake = new DataObjectFake([]);
$resolver = new DataObjectLowerCamelResolver();
$info = new ResolveInfo([
'fieldName' => 'customGetter'
]);
$this->assertEquals('customGetterValue', $resolver->resolve($fake, [], [], $info));
}

public function testResolvesMethod()
{
$fake = new DataObjectFake([]);
$resolver = new DataObjectLowerCamelResolver();
$info = new ResolveInfo([
'fieldName' => 'customMethod'
]);
$this->assertEquals('customMethodValue', $resolver->resolve($fake, [], [], $info));
}
}
25 changes: 25 additions & 0 deletions tests/TypeCreatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,4 +106,29 @@ public function testGetFieldsUsesResolverMethod()
$this->assertArrayHasKey('resolve', $fields['fieldA']);
$this->assertArrayNotHasKey('resolve', $fields['fieldB']);
}

public function testGetFieldsUsesAllFieldsResolverMethod()
{
$mock = $this->getMockBuilder(TypeCreator::class)
->setMethods(['fields','resolveField'])
->getMock();
$mock->method('fields')->willReturn([
'fieldA' => [
'type' => Type::string(),
],
'fieldB' => [
'type' => Type::string(),
],
]);
$mock->method('resolveField')
->willReturn('resolved');

$fields = $mock->getFields();
$this->assertArrayHasKey('fieldA', $fields);
$this->assertArrayHasKey('fieldB', $fields);
$this->assertArrayHasKey('resolve', $fields['fieldA']);
$this->assertArrayHasKey('resolve', $fields['fieldB']);
$this->assertEquals('resolved', $fields['fieldA']['resolve']());
$this->assertEquals('resolved', $fields['fieldB']['resolve']());
}
}

0 comments on commit 5781397

Please sign in to comment.