From 35f1ebd30a57ee2b16d9f1bd3ee01fce6fd83276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Or=C5=82owski?= Date: Thu, 1 Jun 2017 12:54:58 +0200 Subject: [PATCH 1/3] compatible with guzzle 6.x --- src/Client/BatchRequestFailureException.php | 16 ++--- src/Client/Client.php | 45 ++++++------ src/Client/ClientCached.php | 22 +++--- src/Request/CachedRequest.php | 7 +- src/Request/Request.php | 3 +- .../Assertis/Tests/Http/CachedClientTest.php | 69 ++++++------------- tests/Assertis/Tests/Http/ClientTest.php | 38 +++++----- 7 files changed, 85 insertions(+), 115 deletions(-) diff --git a/src/Client/BatchRequestFailureException.php b/src/Client/BatchRequestFailureException.php index 3904f8a..d0af166 100644 --- a/src/Client/BatchRequestFailureException.php +++ b/src/Client/BatchRequestFailureException.php @@ -4,7 +4,6 @@ use Assertis\Http\Request\BatchRequest; use Exception; -use GuzzleHttp\BatchResults; /** * @author MichaƂ Tatarynowicz @@ -16,20 +15,17 @@ class BatchRequestFailureException extends Exception */ private $batchRequest; /** - * @var BatchResults + * @var array */ private $batchResults; /** * @param BatchRequest $batchRequest - * @param BatchResults $batchResults + * @param array $batchResults */ - public function __construct(BatchRequest $batchRequest, BatchResults $batchResults) + public function __construct(BatchRequest $batchRequest, array $batchResults) { - $message = sprintf( - 'Encountered %d failures while performing a batch request.', - count($batchResults->getFailures()) - ); + $message = 'Encountered failures while performing a batch request.'; parent::__construct($message); @@ -46,9 +42,9 @@ public function getBatchRequest(): BatchRequest } /** - * @return BatchResults + * @return array */ - public function getBatchResults(): BatchResults + public function getBatchResults(): array { return $this->batchResults; } diff --git a/src/Client/Client.php b/src/Client/Client.php index 3c707ff..5ff9136 100644 --- a/src/Client/Client.php +++ b/src/Client/Client.php @@ -1,4 +1,4 @@ - */ -class Client implements ClientInterface +class Client //implements ClientInterface { /** * Http client @@ -39,13 +41,19 @@ public function __construct(GuzzleClientInterface $http) */ public function createRequest(Request $request): RequestInterface { - $settings = [ - 'body' => $request->getBody(), - 'query' => $request->getQuery(), - 'headers' => $request->getHeaders(), - ]; + $body = $request->getBody(); + $headers = $request->getHeaders(); + $query = empty($request->getQuery()) ? "" : "?{$request->getQuery()}"; + $rawBaseUrl = $this->guzzleClient->getConfig("base_url"); + if(empty($rawBaseUrl)){ + throw new RuntimeException("Base url is not provided!"); + } + // trimming is here to avoid issues with "/" - too much slashes or missing slashes. + $baseUrl = rtrim($rawBaseUrl, "/"); + $url = "/".ltrim($request->getUrl(),'/'); + $uri = new Uri($baseUrl . $url . $query); - return $this->guzzleClient->createRequest($request->getType(), $request->getUrl(), $settings); + return new GuzzleRequest($request->getType(), $uri, $headers, $body); } /** @@ -79,11 +87,13 @@ public function sendBatch(BatchRequest $batchRequest): array $requests = array_map([$this, 'createRequest'], $batchRequest->getRequests()); $batchResults = Pool::batch($this->guzzleClient, $requests); - if ($batchResults->getFailures()) { - throw new BatchRequestFailureException($batchRequest, $batchResults); + foreach ($batchResults as $result){ + if($result instanceof Exception){ + throw new BatchRequestFailureException($batchRequest, $batchResults); + } } - return $batchResults->getSuccessful(); + return $batchResults; } /** @@ -94,11 +104,4 @@ public function getGuzzleClient() return $this->guzzleClient; } - /** - * @inheritdoc - */ - public function attachSubscriber(SubscriberInterface $subscriber) - { - $this->guzzleClient->getEmitter()->attach($subscriber); - } } diff --git a/src/Client/ClientCached.php b/src/Client/ClientCached.php index f88d58d..bae0558 100644 --- a/src/Client/ClientCached.php +++ b/src/Client/ClientCached.php @@ -5,7 +5,8 @@ use Assertis\Http\Request\CachedBatchRequest; use Assertis\Http\Request\CachedRequest; use GuzzleHttp\Client as GuzzleClient; -use Memcache; +use Memcached; +use Psr\Http\Message\ResponseInterface; /** * Caching implementation for http client for nrs service. @@ -15,15 +16,15 @@ class ClientCached extends Client { /** - * @var Memcache + * @var Memcached */ private $memcache; /** * @param GuzzleClient $http - * @param Memcache $memcache + * @param Memcached $memcache */ - public function __construct(GuzzleClient $http, Memcache $memcache) + public function __construct(GuzzleClient $http, Memcached $memcache) { parent::__construct($http); $this->memcache = $memcache; @@ -37,15 +38,17 @@ public function __construct(GuzzleClient $http, Memcache $memcache) */ public function sendCached(CachedRequest $request) { - $cached = $this->memcache->get($request->getCacheKey()); + $k = $request->getCacheKey(); + $cached = $this->memcache->get($k); if (false !== $cached) { return $cached; } $response = $this->send($request); - $this->memcache->set($request->getCacheKey(), (string)$response->getBody(), 0, $request->getCacheFor()); + $body = $response->getBody()->getContents(); + $this->memcache->set($request->getCacheKey(), $body, 0); - return $response->getBody(); + return $body; } /** @@ -64,11 +67,12 @@ public function sendCachedBatch(CachedBatchRequest $batchRequest) $responses = $this->sendBatch($batchRequest); $out = []; + /* @var ResponseInterface $response */ foreach ($responses as $response) { - $out[] = is_object($response) ? (string)$response->getBody() : null; + $out[] = is_object($response) ? (string)$response->getBody()->getContents() : null; } - $this->memcache->set($batchRequest->getCacheKey(), serialize($out), 0, $batchRequest->getCacheFor()); + $this->memcache->set($batchRequest->getCacheKey(), serialize($out)); return $out; } diff --git a/src/Request/CachedRequest.php b/src/Request/CachedRequest.php index c83781c..3eeae43 100644 --- a/src/Request/CachedRequest.php +++ b/src/Request/CachedRequest.php @@ -24,12 +24,11 @@ class CachedRequest extends Request private $cacheKey; /** - * Create request to send by http - * + * CachedRequest constructor. * @param string $url * @param string $body - * @param string $cacheKey - * @param int $cacheFor + * @param array $cacheKey + * @param string $cacheFor * @param string $type */ public function __construct($url, $body, $cacheKey, $cacheFor, $type = self::DEFAULT_TYPE) diff --git a/src/Request/Request.php b/src/Request/Request.php index 3d9aec6..c262bda 100644 --- a/src/Request/Request.php +++ b/src/Request/Request.php @@ -15,6 +15,7 @@ class Request const POST = 'POST'; const GET = 'GET'; const PUT = 'PUT'; + const DELETE = 'DELETE'; const DEFAULT_TYPE = self::POST; @@ -114,7 +115,7 @@ public function getUrl() */ public function getQuery() { - return $this->query; + return http_build_query($this->query); } /** diff --git a/tests/Assertis/Tests/Http/CachedClientTest.php b/tests/Assertis/Tests/Http/CachedClientTest.php index dfc622d..56cffc3 100644 --- a/tests/Assertis/Tests/Http/CachedClientTest.php +++ b/tests/Assertis/Tests/Http/CachedClientTest.php @@ -7,13 +7,11 @@ use Assertis\Http\Request\CachedRequest; use Assertis\Http\Request\Request; use GuzzleHttp\Client as GuzzleClient; -use GuzzleHttp\Collection; -use GuzzleHttp\Event\EmitterInterface; -use GuzzleHttp\Message\FutureResponse; -use GuzzleHttp\Message\RequestInterface; -use Memcache; +use Memcached; use PHPUnit_Framework_MockObject_MockObject; use PHPUnit_Framework_TestCase; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\StreamInterface; /** * @author loki @@ -22,7 +20,7 @@ class CachedClientTest extends PHPUnit_Framework_TestCase { /** - * @var Memcache|PHPUnit_Framework_MockObject_MockObject + * @var Memcached|PHPUnit_Framework_MockObject_MockObject */ private $memcacheMock; @@ -32,12 +30,7 @@ class CachedClientTest extends PHPUnit_Framework_TestCase private $guzzleClientMock; /** - * @var RequestInterface|PHPUnit_Framework_MockObject_MockObject - */ - private $guzzleRequestMock; - - /** - * @var FutureResponse|PHPUnit_Framework_MockObject_MockObject + * @var ResponseInterface|PHPUnit_Framework_MockObject_MockObject */ private $httpResponseMock; @@ -60,50 +53,30 @@ class CachedClientTest extends PHPUnit_Framework_TestCase protected function setUp() { - $this->memcacheMock = $this->getMock(Memcache::class, ['get', 'set']); - $this->guzzleClientMock = $this->getMockBuilder(GuzzleClient::class) - ->setMethods(['createRequest', 'send']) - ->disableOriginalConstructor() - ->getMock(); - $this->httpResponseMock = $this->getMockBuilder(FutureResponse::class) - ->disableOriginalConstructor() - ->getMock(); - $this->requestMock = $this->getMockBuilder(Request::class) - ->disableOriginalConstructor() - ->getMock(); - $this->cachedRequestMock = $this->getMockBuilder(CachedRequest::class) - ->setMethods(['getCacheKey', 'getCacheFor']) - ->disableOriginalConstructor() - ->getMock(); - $this->cachedBatchRequestMock = $this->getMockBuilder(CachedBatchRequest::class) - ->setMethods(['getCacheKey', 'getCacheFor']) - ->disableOriginalConstructor() - ->getMock(); - - $config = new Collection(); - $emitter = $this->getMock(EmitterInterface::class); - $this->guzzleRequestMock = $this->getMockBuilder(RequestInterface::class)->getMock(); - $this->guzzleRequestMock->expects($this->any())->method('getConfig')->willReturn($config); - $this->guzzleRequestMock->expects($this->any())->method('getEmitter')->willReturn($emitter); + $this->memcacheMock = $this->createMock(Memcached::class); + $this->guzzleClientMock = $this->createMock(GuzzleClient::class); + $this->guzzleClientMock->method('getConfig')->with('base_url')->willReturn("http://test"); + $this->httpResponseMock = $this->createMock(ResponseInterface::class); + $this->requestMock = $this->createMock(Request::class); + $this->cachedRequestMock = $this->createMock(CachedRequest::class); + $this->cachedRequestMock->method('getQuery')->willReturn(""); + $this->cachedRequestMock->method('getUrl')->willReturn(""); + $this->cachedRequestMock->method('getHeaders')->willReturn([]); + $this->cachedBatchRequestMock = $this->createMock(CachedBatchRequest::class); } public function testSendCachedWithoutCacheMakesRequest() { $cacheKey = 'CACHE_KEY'; - $cacheFor = 100; $body = 'BODY'; + $this->memcacheMock->method('get')->willReturn(false); $this->cachedRequestMock->expects($this->any())->method('getCacheKey')->willReturn($cacheKey); - $this->cachedRequestMock->expects($this->once())->method('getCacheFor')->willReturn($cacheFor); - - $this->httpResponseMock->expects($this->any())->method('getBody')->willReturn($body); - - $this->guzzleClientMock->expects($this->once())->method('createRequest')->willReturn($this->guzzleRequestMock); + $stream = $this->createMock(StreamInterface::class); + $stream->method('getContents')->willReturn($body); + $this->httpResponseMock->expects($this->any())->method('getBody')->willReturn($stream); $this->guzzleClientMock->expects($this->once())->method('send')->willReturn($this->httpResponseMock); - $this->memcacheMock->expects($this->once())->method('get')->with($cacheKey)->willReturn(false); - $this->memcacheMock->expects($this->once())->method('set')->with($cacheKey, $body, 0, $cacheFor); - $client = new ClientCached($this->guzzleClientMock, $this->memcacheMock); $this->assertSame($body, $client->sendCached($this->cachedRequestMock)); } @@ -114,11 +87,9 @@ public function testSendCachedWithCacheReturnsCache() $body = 'BODY'; $this->cachedRequestMock->expects($this->any())->method('getCacheKey')->willReturn($cacheKey); - $this->cachedRequestMock->expects($this->never())->method('getCacheFor'); - $this->guzzleClientMock->expects($this->never())->method('send'); - $this->memcacheMock->expects($this->once())->method('get')->with($cacheKey)->willReturn($body); + $this->memcacheMock->expects($this->once())->method('get')->with($cacheKey,null,null)->willReturn($body); $this->memcacheMock->expects($this->never())->method('set'); $client = new ClientCached($this->guzzleClientMock, $this->memcacheMock); diff --git a/tests/Assertis/Tests/Http/ClientTest.php b/tests/Assertis/Tests/Http/ClientTest.php index 17921a2..2b708a9 100644 --- a/tests/Assertis/Tests/Http/ClientTest.php +++ b/tests/Assertis/Tests/Http/ClientTest.php @@ -5,10 +5,10 @@ use Assertis\Http\Client\Client; use Assertis\Http\Request\Request; use GuzzleHttp\Client as GuzzleClient; -use GuzzleHttp\Message\RequestInterface; -use GuzzleHttp\Message\ResponseInterface; use PHPUnit_Framework_MockObject_MockObject; use PHPUnit_Framework_TestCase; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; /** * @author loki @@ -37,15 +37,14 @@ protected function setUp() public function testShouldCreateRequest() { - $request = new Request('/', self::BODY); + $request = new Request('endpoint', self::BODY); $createdRequest = $this->client->createRequest($request); - $this->assertEquals(self::BODY, $createdRequest->getBody()); - $this->assertEquals('', urldecode((string)$createdRequest->getQuery())); - $this->assertEquals(80, $createdRequest->getPort()); - $this->assertEquals('http', $createdRequest->getScheme()); - $this->assertEquals('test', $createdRequest->getHost()); + $this->assertEquals(self::BODY, $createdRequest->getBody()->getContents()); + $this->assertEquals('', urldecode((string)$createdRequest->getUri()->getQuery())); + $this->assertEquals('http', $createdRequest->getUri()->getScheme()); + $this->assertEquals('test', $createdRequest->getUri()->getHost()); $this->assertEquals('POST', $createdRequest->getMethod()); - $this->assertEquals('/', $createdRequest->getPath()); + $this->assertEquals('/endpoint', $createdRequest->getUri()->getPath()); } public function testShouldCreateRequestWithQuery() @@ -59,33 +58,30 @@ public function testShouldCreateRequestWithQuery() $request = new Request("/", '', $query); $createdRequest = $this->client->createRequest($request); $this->assertEquals('', $createdRequest->getBody()); - $this->assertEquals('foo=bar&test[x]=y', urldecode((string)$createdRequest->getQuery())); - $this->assertEquals(80, $createdRequest->getPort()); - $this->assertEquals('http', $createdRequest->getScheme()); - $this->assertEquals('test', $createdRequest->getHost()); + $this->assertEquals('foo=bar&test[x]=y', urldecode((string)$createdRequest->getUri()->getQuery())); + $this->assertEquals('http', $createdRequest->getUri()->getScheme()); + $this->assertEquals('test', $createdRequest->getUri()->getHost()); $this->assertEquals('POST', $createdRequest->getMethod()); - $this->assertEquals('/', $createdRequest->getPath()); + $this->assertEquals('/', $createdRequest->getUri()->getPath()); } public function testSendShouldCreateRequestAndSendIt() { - /** @var RequestInterface|PHPUnit_Framework_MockObject_MockObject $httpRequest */ - $httpRequest = $this->getMockBuilder(RequestInterface::class)->getMock(); - /** @var GuzzleClient|PHPUnit_Framework_MockObject_MockObject $httpClient */ $httpClient = $this->getMockBuilder(GuzzleClient::class) ->disableOriginalConstructor() ->getMock(); - $httpClient->expects($this->once()) - ->method('createRequest') - ->willReturn($httpRequest); - $httpClient->expects($this->once()) ->method('send') ->with($this->isInstanceOf(RequestInterface::class)) ->willReturn($this->getMockForAbstractClass(ResponseInterface::class)); + $httpClient + ->method('getConfig') + ->with('base_url') + ->willReturn("http://test"); + $request = new Request('/', self::BODY); $client = new Client($httpClient); $client->send($request); From ad91923539b00a28af05a5dd65c8852d137f1682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Or=C5=82owski?= Date: Thu, 1 Jun 2017 12:57:42 +0200 Subject: [PATCH 2/3] self-review --- src/Client/Client.php | 2 +- src/Client/ClientInterface.php | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/Client/Client.php b/src/Client/Client.php index 5ff9136..a7ea6e0 100644 --- a/src/Client/Client.php +++ b/src/Client/Client.php @@ -19,7 +19,7 @@ * * @author Maciej Romanski */ -class Client //implements ClientInterface +class Client implements ClientInterface { /** * Http client diff --git a/src/Client/ClientInterface.php b/src/Client/ClientInterface.php index 7e03944..235079d 100644 --- a/src/Client/ClientInterface.php +++ b/src/Client/ClientInterface.php @@ -4,9 +4,8 @@ use Assertis\Http\Request\BatchRequest; use Assertis\Http\Request\Request; -use GuzzleHttp\Event\SubscriberInterface; -use GuzzleHttp\Message\RequestInterface; -use GuzzleHttp\Message\ResponseInterface; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; /** * Http client interface @@ -37,10 +36,4 @@ public function send(Request $request): ResponseInterface; */ public function sendBatch(BatchRequest $requests): array; - /** - * Attach a subscriber that gets notified of requests. - * - * @param SubscriberInterface $subscriber - */ - public function attachSubscriber(SubscriberInterface $subscriber); } From 6e87efe4dd43c78f3b461a9ca8d5112000631784 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Or=C5=82owski?= Date: Thu, 1 Jun 2017 13:26:56 +0200 Subject: [PATCH 3/3] fixes after review --- src/Client/BatchRequestFailureException.php | 10 +- src/Client/Client.php | 13 +- src/Client/ClientInterface.php | 5 +- src/Request/Request.php | 2 +- src/Response/BatchResult.php | 162 ++++++++++++++++++++ 5 files changed, 179 insertions(+), 13 deletions(-) create mode 100644 src/Response/BatchResult.php diff --git a/src/Client/BatchRequestFailureException.php b/src/Client/BatchRequestFailureException.php index d0af166..fe9be41 100644 --- a/src/Client/BatchRequestFailureException.php +++ b/src/Client/BatchRequestFailureException.php @@ -3,6 +3,7 @@ namespace Assertis\Http\Client; use Assertis\Http\Request\BatchRequest; +use Assertis\Http\Response\BatchResults; use Exception; /** @@ -21,11 +22,14 @@ class BatchRequestFailureException extends Exception /** * @param BatchRequest $batchRequest - * @param array $batchResults + * @param BatchResults $batchResults */ - public function __construct(BatchRequest $batchRequest, array $batchResults) + public function __construct(BatchRequest $batchRequest, BatchResults $batchResults) { - $message = 'Encountered failures while performing a batch request.'; + $message = sprintf( + 'Encountered %d failures while performing a batch request.', + count($batchResults->getFailures()) + ); parent::__construct($message); diff --git a/src/Client/Client.php b/src/Client/Client.php index a7ea6e0..503b7e8 100644 --- a/src/Client/Client.php +++ b/src/Client/Client.php @@ -4,6 +4,7 @@ use Assertis\Http\Request\BatchRequest; use Assertis\Http\Request\Request; +use Assertis\Http\Response\BatchResults; use Exception; use GuzzleHttp\ClientInterface as GuzzleClientInterface; use GuzzleHttp\Exception\RequestException; @@ -43,7 +44,7 @@ public function createRequest(Request $request): RequestInterface { $body = $request->getBody(); $headers = $request->getHeaders(); - $query = empty($request->getQuery()) ? "" : "?{$request->getQuery()}"; + $query = empty($request->getQuery()) ? "" : "?".http_build_query($request->getQuery()); $rawBaseUrl = $this->guzzleClient->getConfig("base_url"); if(empty($rawBaseUrl)){ throw new RuntimeException("Base url is not provided!"); @@ -82,15 +83,13 @@ public function send(Request $request): ResponseInterface /** * @inheritdoc */ - public function sendBatch(BatchRequest $batchRequest): array + public function sendBatch(BatchRequest $batchRequest): BatchResults { $requests = array_map([$this, 'createRequest'], $batchRequest->getRequests()); - $batchResults = Pool::batch($this->guzzleClient, $requests); + $batchResults = new BatchResults(Pool::batch($this->guzzleClient, $requests)); - foreach ($batchResults as $result){ - if($result instanceof Exception){ - throw new BatchRequestFailureException($batchRequest, $batchResults); - } + if ($batchResults->getFailures()) { + throw new BatchRequestFailureException($batchRequest, $batchResults); } return $batchResults; diff --git a/src/Client/ClientInterface.php b/src/Client/ClientInterface.php index 235079d..fc5206c 100644 --- a/src/Client/ClientInterface.php +++ b/src/Client/ClientInterface.php @@ -4,6 +4,7 @@ use Assertis\Http\Request\BatchRequest; use Assertis\Http\Request\Request; +use Assertis\Http\Response\BatchResults; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; @@ -32,8 +33,8 @@ public function send(Request $request): ResponseInterface; * Send multiple requests in parallel. * * @param BatchRequest $requests - * @return ResponseInterface[] + * @return BatchResults */ - public function sendBatch(BatchRequest $requests): array; + public function sendBatch(BatchRequest $requests): BatchResults; } diff --git a/src/Request/Request.php b/src/Request/Request.php index c262bda..e28351e 100644 --- a/src/Request/Request.php +++ b/src/Request/Request.php @@ -115,7 +115,7 @@ public function getUrl() */ public function getQuery() { - return http_build_query($this->query); + return $this->query; } /** diff --git a/src/Response/BatchResult.php b/src/Response/BatchResult.php new file mode 100644 index 0000000..9e7c107 --- /dev/null +++ b/src/Response/BatchResult.php @@ -0,0 +1,162 @@ +attach($obj); + } + $this->hash = $hash; + } + + /** + * Get the keys that are available on the batch result. + * + * @return array + */ + public function getKeys() + { + return iterator_to_array($this->hash); + } + + /** + * Gets a result from the container for the given object. When getting + * results for a batch of requests, provide the request object. + * + * @param object $forObject Object to retrieve the result for. + * + * @return mixed|null + */ + public function getResult($forObject) + { + return isset($this->hash[$forObject]) ? $this->hash[$forObject] : null; + } + + /** + * Get an array of successful results. + * + * @return array + */ + public function getSuccessful() + { + $results = []; + foreach ($this->hash as $key) { + if (!($this->hash[$key] instanceof \Exception)) { + $results[] = $this->hash[$key]; + } + } + + return $results; + } + + /** + * Get an array of failed results. + * + * @return array + */ + public function getFailures() + { + $results = []; + foreach ($this->hash as $key) { + if ($this->hash[$key] instanceof \Exception) { + $results[] = $this->hash[$key]; + } + } + + return $results; + } + + /** + * Allows iteration over all batch result values. + * + * @return ArrayIterator + */ + public function getIterator() + { + $results = []; + foreach ($this->hash as $key) { + $results[] = $this->hash[$key]; + } + + return new ArrayIterator($results); + } + + /** + * Counts the number of elements in the batch result. + * + * @return int + */ + public function count() + { + return count($this->hash); + } + + /** + * Checks if the batch contains a specific numerical array index. + * + * @param int $key Index to access + * + * @return bool + */ + public function offsetExists($key) + { + return $key < count($this->hash); + } + + /** + * Allows access of the batch using a numerical array index. + * + * @param int $key Index to access. + * + * @return mixed|null + */ + public function offsetGet($key) + { + $i = -1; + foreach ($this->hash as $obj) { + if ($key === ++$i) { + return $this->hash[$obj]; + } + } + + return null; + } + + public function offsetUnset($key) + { + throw new RuntimeException('Not implemented'); + } + + public function offsetSet($key, $value) + { + throw new RuntimeException('Not implemented'); + } +}