Skip to content

Commit cde0db0

Browse files
authored
Merge branch 'master' into feature/conditional-resolver
2 parents 6f63f2a + df1b1fa commit cde0db0

File tree

6 files changed

+226
-4
lines changed

6 files changed

+226
-4
lines changed

src/DefinitionIterator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public function get($lookup, $definition = null)
5353
{
5454
$updateContext = false;
5555

56-
if ($this->isContextFullyPopulated($lookup)) {
56+
if ($definition === null && $this->isContextFullyPopulated($lookup)) {
5757
$value = $this->context->get($lookup);
5858

5959
return ($value instanceof Context) ? $value->toArray() : $value;

src/Resolver/Service.php

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Upward\Resolver;
10+
11+
use Magento\Upward\Definition;
12+
use Zend\Http\Client;
13+
14+
class Service extends AbstractResolver
15+
{
16+
/**
17+
* {@inheritdoc}
18+
*/
19+
public function getIndicator(): string
20+
{
21+
return 'url';
22+
}
23+
24+
/**
25+
* {@inheritdoc}
26+
*/
27+
public function isValid(Definition $definition): bool
28+
{
29+
if (!$definition->has('query')) {
30+
return false;
31+
}
32+
33+
if ($definition->has('method')) {
34+
$method = $this->getIterator()->get('method', $definition);
35+
if (!\in_array($method, ['GET', 'POST'])) {
36+
return false;
37+
}
38+
}
39+
40+
return parent::isValid($definition);
41+
}
42+
43+
/**
44+
* {@inheritdoc}
45+
*/
46+
public function resolve($definition)
47+
{
48+
if (!$definition instanceof Definition) {
49+
throw new \InvalidArgumentException('$definition must be an instance of ' . Definition::class);
50+
}
51+
52+
$url = $this->getIterator()->get('url', $definition);
53+
$query = $this->getIterator()->get('query', $definition);
54+
$method = $definition->has('method') ? $this->getIterator()->get('method', $definition) : 'POST';
55+
$headers = $definition->has('headers') ? $this->getIterator()->get('headers', $definition) : [];
56+
$variables = $definition->has('variables') ? $this->getIterator()->get('variables', $definition) : [];
57+
$requestParams = [
58+
'query' => $query,
59+
'variables' => $variables,
60+
];
61+
62+
$client = new Client($url);
63+
$client->setMethod($method);
64+
$client->setHeaders($headers);
65+
if ($method === 'POST') {
66+
$client->setRawBody(json_encode($requestParams));
67+
} elseif ($method === 'GET') {
68+
$client->setParameterGet($requestParams);
69+
}
70+
71+
$response = $client->send();
72+
73+
return json_decode($response->getBody(), true);
74+
}
75+
}

src/ResolverFactory.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class ResolverFactory
2727
self::RESOLVER_TYPE_FILE => Resolver\File::class,
2828
self::RESOLVER_TYPE_INLINE => Resolver\Inline::class,
2929
self::RESOLVER_TYPE_PROXY => Resolver\Proxy::class,
30+
self::RESOLVER_TYPE_SERVICE => Resolver\Service::class,
3031
self::RESOLVER_TYPE_TEMPLATE => Resolver\Template::class,
3132
];
3233

test/DefinitionIteratorTest.php

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,13 @@ public function testIteratingDefinitionTree(): void
165165

166166
public function testLookupInContext(): void
167167
{
168-
$context = new Context(['key' => 'context value']);
169-
$definition = new Definition([]);
170-
$iterator = new DefinitionIterator($definition, $context);
168+
$context = new Context(['key' => 'context value']);
169+
$definition = new Definition([]);
170+
$iterator = new DefinitionIterator($definition, $context);
171+
$definitionWithSameKey = new Definition(['key' => true]);
171172

172173
verify($iterator->get('key'))->is()->sameAs('context value');
174+
verify($iterator->get('key', $definitionWithSameKey))->is()->sameAs(true);
173175
}
174176

175177
public function testResolverValueDefinition(): void

test/Resolver/ProxyTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818
use Zend\Http\Response;
1919
use function BeBat\Verify\verify;
2020

21+
/**
22+
* @runTestsInSeparateProcesses
23+
*/
2124
class ProxyTest extends TestCase
2225
{
2326
use MockeryPHPUnitIntegration;

test/Resolver/ServiceTest.php

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
declare(strict_types=1);
8+
9+
namespace Magento\Upward\Test\Resolver;
10+
11+
use Magento\Upward\Definition;
12+
use Magento\Upward\DefinitionIterator;
13+
use Magento\Upward\Resolver\Service;
14+
use Mockery;
15+
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
16+
use PHPUnit\Framework\TestCase;
17+
use Zend\Http\Client;
18+
use Zend\Http\Response;
19+
use function BeBat\Verify\verify;
20+
21+
/**
22+
* @runTestsInSeparateProcesses
23+
*/
24+
class ServiceTest extends TestCase
25+
{
26+
use MockeryPHPUnitIntegration;
27+
28+
/**
29+
* @var DefinitionIterator|Mockery\MockInterface
30+
*/
31+
private $definitionIteratorMock;
32+
33+
/**
34+
* @var Service
35+
*/
36+
private $resolver;
37+
38+
protected function setUp(): void
39+
{
40+
$this->resolver = new Service();
41+
$this->definitionIteratorMock = Mockery::mock(DefinitionIterator::class);
42+
$this->resolver->setIterator($this->definitionIteratorMock);
43+
}
44+
45+
public function testIndicator(): void
46+
{
47+
verify($this->resolver->getIndicator())->is()->sameAs('url');
48+
}
49+
50+
public function testIsValid(): void
51+
{
52+
$validDefinition = new Definition(['url' => '/graphql', 'query' => 'gql']);
53+
$validWithMethodDefinition = new Definition(['url' => '/graphql', 'query' => 'gql', 'method' => 'GET']);
54+
$invalidNoURL = new Definition(['query' => 'gql']);
55+
$invalidNoQuery = new Definition(['url' => '/graphql']);
56+
$invalidUnsupportedMethod = new Definition(['url' => '/graphql', 'query' => 'gql', 'method' => 'PUT']);
57+
58+
$this->definitionIteratorMock->shouldReceive('get')
59+
->twice()
60+
->with('method', Mockery::type(Definition::class))
61+
->andReturnUsing(function (string $key, Definition $definition) {
62+
return $definition->get($key);
63+
});
64+
65+
verify($this->resolver->isValid($validDefinition))->is()->true();
66+
verify($this->resolver->isValid($validWithMethodDefinition))->is()->true();
67+
verify($this->resolver->isValid($invalidNoURL))->is()->false();
68+
verify($this->resolver->isValid($invalidNoQuery))->is()->false();
69+
verify($this->resolver->isValid($invalidUnsupportedMethod))->is()->false();
70+
}
71+
72+
public function testResolve(): void
73+
{
74+
$definition = new Definition(['url' => '/graphql', 'query' => 'gql']);
75+
$expectedRequestBody = json_encode(['query' => 'gql', 'variables' => []]);
76+
$expectedResponseArray = ['data' => ['key' => 'value']];
77+
78+
$this->definitionIteratorMock->shouldReceive('get')
79+
->twice()
80+
->with(Mockery::type('string'), Mockery::type(Definition::class))
81+
->andReturnUsing(function (string $key, Definition $definition) {
82+
return $definition->get($key);
83+
});
84+
85+
$responseMock = Mockery::mock(Response::class);
86+
$responseMock->shouldReceive('getBody')->andReturn('{"data":{"key":"value"}}');
87+
88+
$zendClientMock = Mockery::mock('overload:' . Client::class);
89+
$zendClientMock->shouldReceive('setMethod')->with('POST');
90+
$zendClientMock->shouldReceive('setHeaders')->with([]);
91+
$zendClientMock->shouldReceive('setRawBody')->with($expectedRequestBody);
92+
$zendClientMock->shouldReceive('send')->andReturn($responseMock);
93+
94+
verify($this->resolver->resolve($definition))->is()->sameAs($expectedResponseArray);
95+
}
96+
97+
public function testResolveThrowsException(): void
98+
{
99+
$this->expectException(\InvalidArgumentException::class);
100+
$this->expectExceptionMessage('$definition must be an instance of Magento\\Upward\\Definition');
101+
102+
$this->resolver->resolve('Not a Definition');
103+
}
104+
105+
public function testResolveWithConfiguration(): void
106+
{
107+
$definition = new Definition([
108+
'url' => '/graphql',
109+
'query' => 'gql',
110+
'variables' => [
111+
'var1' => 'var1Value',
112+
],
113+
'headers' => [
114+
'header' => 'headerValue',
115+
],
116+
'method' => 'GET',
117+
]);
118+
$expectedRequestBody = ['query' => 'gql', 'variables' => ['var1' => 'var1Value']];
119+
$expectedResponseArray = ['data' => ['key' => 'value']];
120+
121+
$this->definitionIteratorMock->shouldReceive('get')
122+
->times(5)
123+
->with(Mockery::type('string'), Mockery::type(Definition::class))
124+
->andReturnUsing(function (string $key, Definition $definition) {
125+
$returnValue = $definition->get($key);
126+
127+
return $returnValue instanceof Definition ? $returnValue->toArray() : $returnValue;
128+
});
129+
130+
$responseMock = Mockery::mock(Response::class);
131+
$responseMock->shouldReceive('getBody')->andReturn('{"data":{"key":"value"}}');
132+
133+
$zendClientMock = Mockery::mock('overload:' . Client::class);
134+
$zendClientMock->shouldReceive('setMethod')->with('GET');
135+
$zendClientMock->shouldReceive('setHeaders')->with(['header' => 'headerValue']);
136+
$zendClientMock->shouldReceive('setParameterGet')->with($expectedRequestBody);
137+
$zendClientMock->shouldReceive('send')->andReturn($responseMock);
138+
139+
verify($this->resolver->resolve($definition))->is()->sameAs($expectedResponseArray);
140+
}
141+
}

0 commit comments

Comments
 (0)