/** * Get all of the received requests * * @param bool $hydrate Set to TRUE to turn the messages into * actual {@see RequestInterface} objects. If $hydrate is FALSE, * requests will be returned as strings. * * @return array * @throws \RuntimeException */ public static function received($hydrate = false) { $response = TestServer::received(); if ($hydrate) { $c = new Client(); $factory = new MessageFactory(); $response = array_map(function ($message) use($factory, $c) { return RingBridge::fromRingRequest($message); }, $response); } return $response; }
/** * Runs the state machine until a terminal state is entered or the * optionally supplied $finalState is entered. * * @param Transaction $trans Transaction being transitioned. * * @throws \Exception if a terminal state throws an exception. */ public function __invoke(Transaction $trans) { $trans->_transitionCount = 0; if (!$trans->state) { $trans->state = 'before'; } transition: if (++$trans->_transitionCount > $this->maxTransitions) { throw new StateException("Too many state transitions were " . "encountered ({$trans->_transitionCount}). This likely " . "means that a combination of event listeners are in an " . "infinite loop."); } switch ($trans->state) { case 'before': goto before; case 'complete': goto complete; case 'error': goto error; case 'retry': goto retry; case 'send': goto send; case 'end': goto end; default: throw new StateException("Invalid state: {$trans->state}"); } before: try { $trans->request->getEmitter()->emit('before', new BeforeEvent($trans)); $trans->state = 'send'; if ((bool) $trans->response) { $trans->state = 'complete'; } } catch (\Exception $e) { $trans->state = 'error'; $trans->exception = $e; } goto transition; complete: try { if ($trans->response instanceof FutureInterface) { // Futures will have their own end events emitted when // dereferenced. return; } $trans->state = 'end'; $trans->response->setEffectiveUrl($trans->request->getUrl()); $trans->request->getEmitter()->emit('complete', new CompleteEvent($trans)); } catch (\Exception $e) { $trans->state = 'error'; $trans->exception = $e; } goto transition; error: try { // Convert non-request exception to a wrapped exception $trans->exception = RequestException::wrapException($trans->request, $trans->exception); $trans->state = 'end'; $trans->request->getEmitter()->emit('error', new ErrorEvent($trans)); // An intercepted request (not retried) transitions to complete if (!$trans->exception && $trans->state !== 'retry') { $trans->state = 'complete'; } } catch (\Exception $e) { $trans->state = 'end'; $trans->exception = $e; } goto transition; retry: $trans->retries++; $trans->response = null; $trans->exception = null; $trans->state = 'before'; goto transition; send: $fn = $this->handler; $trans->response = FutureResponse::proxy($fn(RingBridge::prepareRingRequest($trans)), function ($value) use($trans) { RingBridge::completeRingResponse($trans, $value, $this->mf, $this); $this($trans); return $trans->response; }); return; end: $trans->request->getEmitter()->emit('end', new EndEvent($trans)); // Throw exceptions in the terminal event if the exception // was not handled by an "end" event listener. if ($trans->exception) { if (!$trans->exception instanceof RequestException) { $trans->exception = RequestException::wrapException($trans->request, $trans->exception); } throw $trans->exception; } }
public function testEnsuresResponseOrExceptionWhenCompletingResponse() { $trans = new Transaction(new Client(), new Request('GET', 'http://f.co')); $f = new MessageFactory(); $fsm = new RequestFsm(function () { }, new MessageFactory()); try { RingBridge::completeRingResponse($trans, [], $f, $fsm); } catch (RequestException $e) { $this->assertSame($trans->request, $e->getRequest()); $this->assertContains('RingPHP', $e->getMessage()); } }