Skip to content

Commit c660577

Browse files
committed
Added provider fetch exception handler to ImportConnector.
1 parent 91ecee9 commit c660577

4 files changed

Lines changed: 90 additions & 0 deletions

File tree

src/Connector/ConnectionContext.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,20 @@ final class ConnectionContext
88
{
99
private $mustCache;
1010

11+
/**
12+
* User-defined exception handler called when a recoverable exception is thrown by Connector::fetch().
13+
*
14+
* @var callable
15+
*/
1116
private $fetchExceptionHandler;
1217

18+
/**
19+
* Provider-defined exception handler called when a recoverable exception is thrown by Connector::fetch().
20+
*
21+
* @var callable
22+
*/
23+
private $providerFetchExceptionHandler;
24+
1325
private $maxFetchAttempts;
1426

1527
public function __construct($mustCache, callable $fetchExceptionHandler, $maxFetchAttempts)
@@ -47,9 +59,30 @@ function (\Exception $exception) {
4759
throw $exception;
4860
}
4961

62+
// Call provider's exception handler, if defined.
63+
if ($this->providerFetchExceptionHandler) {
64+
call_user_func($this->providerFetchExceptionHandler, $exception);
65+
}
66+
5067
// TODO Clone exception handler to avoid persisting state between calls.
5168
call_user_func($this->fetchExceptionHandler, $exception);
5269
}
5370
);
5471
}
72+
73+
/**
74+
* Sets an exception handler to be called when a recoverable exception is thrown by Connector::fetch().
75+
*
76+
* This handler is intended to be set by provider resources only and is called before the user-defined handler.
77+
*
78+
* @param callable $providerFetchExceptionHandler Exception handler.
79+
*/
80+
public function setProviderFetchExceptionHandler(callable $providerFetchExceptionHandler)
81+
{
82+
if ($this->providerFetchExceptionHandler !== null) {
83+
throw new \LogicException('Cannot set provider fetch exception handler: already set!');
84+
}
85+
86+
$this->providerFetchExceptionHandler = $providerFetchExceptionHandler;
87+
}
5588
}

src/Connector/ImportConnector.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,14 @@ public function getWrappedConnector()
3939
{
4040
return $this->connector;
4141
}
42+
43+
/**
44+
* Sets the exception handler to be called when a recoverable exception is thrown by Connector::fetch().
45+
*
46+
* @param callable $exceptionHandler Exception handler.
47+
*/
48+
public function setExceptionHandler(callable $exceptionHandler)
49+
{
50+
$this->context->setProviderFetchExceptionHandler($exceptionHandler);
51+
}
4252
}

test/Integration/Porter/PorterTest.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use ScriptFUSION\Porter\Connector\ConnectionContext;
1313
use ScriptFUSION\Porter\Connector\Connector;
1414
use ScriptFUSION\Porter\Connector\ConnectorOptions;
15+
use ScriptFUSION\Porter\Connector\ImportConnector;
1516
use ScriptFUSION\Porter\Connector\RecoverableConnectorException;
1617
use ScriptFUSION\Porter\ImportException;
1718
use ScriptFUSION\Porter\Porter;
@@ -303,6 +304,36 @@ public function testCustomFetchExceptionHandler()
303304
$this->porter->import($this->specification);
304305
}
305306

307+
/**
308+
* Tests that when a provider fetch exception handler is specified and the connector throws a recoverable
309+
* exception, the handler is called before the user handler.
310+
*/
311+
public function testCustomProviderFetchExceptionHandler()
312+
{
313+
$this->specification->setFetchExceptionHandler(function () {
314+
throw new \LogicException('This exception must not be thrown!');
315+
});
316+
317+
$this->arrangeConnectorException($connectorException =
318+
new RecoverableConnectorException('This exception is caught by the provider handler.'));
319+
320+
$this->resource
321+
->shouldReceive('fetch')
322+
->andReturnUsing(function (ImportConnector $connector) use ($connectorException) {
323+
$connector->setExceptionHandler(function (\Exception $exception) use ($connectorException) {
324+
self::assertSame($connectorException, $exception);
325+
326+
throw new \RuntimeException('This exception is thrown by the provider handler.');
327+
});
328+
329+
yield $connector->fetch('foo');
330+
})
331+
;
332+
333+
$this->setExpectedException(\RuntimeException::class);
334+
$this->porter->importOne($this->specification);
335+
}
336+
306337
#endregion
307338

308339
public function testFilter()

test/Unit/Porter/Connector/ImportConnectorTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,20 @@ public function testGetWrappedConnector()
8989

9090
self::assertSame($wrappedConnector, $connector->getWrappedConnector());
9191
}
92+
93+
/**
94+
* Tests that setting the provider exception handler twice produces an exception the second time.
95+
*/
96+
public function testSetExceptionHandlerTwice()
97+
{
98+
$connector = new ImportConnector(
99+
$wrappedConnector = \Mockery::mock(Connector::class),
100+
FixtureFactory::buildConnectionContext()
101+
);
102+
103+
$connector->setExceptionHandler([$this, __FUNCTION__]);
104+
105+
$this->setExpectedException(\LogicException::class);
106+
$connector->setExceptionHandler([$this, __FUNCTION__]);
107+
}
92108
}

0 commit comments

Comments
 (0)