mailgun-php/Mailgun/Guzzle/Plugin/Mock/MockPlugin.php

243 lines
6.7 KiB
PHP
Raw Normal View History

2013-07-18 09:48:12 +04:00
<?php
namespace Guzzle\Plugin\Mock;
use Guzzle\Common\Event;
use Guzzle\Common\Exception\InvalidArgumentException;
use Guzzle\Common\AbstractHasDispatcher;
use Guzzle\Http\Exception\CurlException;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Message\EntityEnclosingRequestInterface;
use Guzzle\Http\Message\Response;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Queues mock responses or exceptions and delivers mock responses or exceptions in a fifo order.
*/
class MockPlugin extends AbstractHasDispatcher implements EventSubscriberInterface, \Countable
{
/** @var array Array of mock responses / exceptions */
protected $queue = array();
/** @var bool Whether or not to remove the plugin when the queue is empty */
protected $temporary = false;
/** @var array Array of requests that were mocked */
protected $received = array();
/** @var bool Whether or not to consume an entity body when a mock response is served */
protected $readBodies;
/**
* @param array $items Array of responses or exceptions to queue
* @param bool $temporary Set to TRUE to remove the plugin when the queue is empty
* @param bool $readBodies Set to TRUE to consume the entity body when a mock is served
*/
public function __construct(array $items = null, $temporary = false, $readBodies = false)
{
$this->readBodies = $readBodies;
$this->temporary = $temporary;
if ($items) {
foreach ($items as $item) {
if ($item instanceof \Exception) {
$this->addException($item);
} else {
$this->addResponse($item);
}
}
}
}
public static function getSubscribedEvents()
{
// Use a number lower than the CachePlugin
return array('request.before_send' => array('onRequestBeforeSend', -999));
}
public static function getAllEvents()
{
return array('mock.request');
}
/**
* Get a mock response from a file
*
* @param string $path File to retrieve a mock response from
*
* @return Response
* @throws InvalidArgumentException if the file is not found
*/
public static function getMockFile($path)
{
if (!file_exists($path)) {
throw new InvalidArgumentException('Unable to open mock file: ' . $path);
}
return Response::fromMessage(file_get_contents($path));
}
/**
* Set whether or not to consume the entity body of a request when a mock
* response is used
*
* @param bool $readBodies Set to true to read and consume entity bodies
*
* @return self
*/
public function readBodies($readBodies)
{
$this->readBodies = $readBodies;
return $this;
}
/**
* Returns the number of remaining mock responses
*
* @return int
*/
public function count()
{
return count($this->queue);
}
/**
* Add a response to the end of the queue
*
* @param string|Response $response Response object or path to response file
*
* @return MockPlugin
* @throws InvalidArgumentException if a string or Response is not passed
*/
public function addResponse($response)
{
if (!($response instanceof Response)) {
if (!is_string($response)) {
throw new InvalidArgumentException('Invalid response');
}
$response = self::getMockFile($response);
}
$this->queue[] = $response;
return $this;
}
/**
* Add an exception to the end of the queue
*
* @param CurlException $e Exception to throw when the request is executed
*
* @return MockPlugin
*/
public function addException(CurlException $e)
{
$this->queue[] = $e;
return $this;
}
/**
* Clear the queue
*
* @return MockPlugin
*/
public function clearQueue()
{
$this->queue = array();
return $this;
}
/**
* Returns an array of mock responses remaining in the queue
*
* @return array
*/
public function getQueue()
{
return $this->queue;
}
/**
* Check if this is a temporary plugin
*
* @return bool
*/
public function isTemporary()
{
return $this->temporary;
}
/**
* Get a response from the front of the list and add it to a request
*
* @param RequestInterface $request Request to mock
*
* @return self
* @throws CurlException When request.send is called and an exception is queued
*/
public function dequeue(RequestInterface $request)
{
$this->dispatch('mock.request', array('plugin' => $this, 'request' => $request));
$item = array_shift($this->queue);
if ($item instanceof Response) {
if ($this->readBodies && $request instanceof EntityEnclosingRequestInterface) {
$request->getEventDispatcher()->addListener('request.sent', $f = function (Event $event) use (&$f) {
while ($data = $event['request']->getBody()->read(8096));
// Remove the listener after one-time use
$event['request']->getEventDispatcher()->removeListener('request.sent', $f);
});
}
$request->setResponse($item);
} elseif ($item instanceof CurlException) {
// Emulates exceptions encountered while transferring requests
$item->setRequest($request);
$state = $request->setState(RequestInterface::STATE_ERROR, array('exception' => $item));
// Only throw if the exception wasn't handled
if ($state == RequestInterface::STATE_ERROR) {
throw $item;
}
}
return $this;
}
/**
* Clear the array of received requests
*/
public function flush()
{
$this->received = array();
}
/**
* Get an array of requests that were mocked by this plugin
*
* @return array
*/
public function getReceivedRequests()
{
return $this->received;
}
/**
* Called when a request is about to be sent
*
* @param Event $event
*/
public function onRequestBeforeSend(Event $event)
{
if ($this->queue) {
$request = $event['request'];
$this->received[] = $request;
// Detach the filter from the client so it's a one-time use
if ($this->temporary && count($this->queue) == 1 && $request->getClient()) {
$request->getClient()->getEventDispatcher()->removeSubscriber($this);
}
$this->dequeue($request);
}
}
}