Skip to content

Commit

Permalink
use __serialize instead of __sleep on CacheEntry (#163)
Browse files Browse the repository at this point in the history
  • Loading branch information
e-zannelli authored May 31, 2023
1 parent 8528f8c commit 0e12dcc
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 31 deletions.
88 changes: 57 additions & 31 deletions src/CacheEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
namespace Kevinrob\GuzzleCache;

use GuzzleHttp\Psr7\PumpStream;
use Psr\Http\Message\MessageInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

class CacheEntry
class CacheEntry implements \Serializable
{
/**
* @var RequestInterface
Expand Down Expand Up @@ -256,47 +257,72 @@ public function getAge()
return time() - $this->dateCreated->getTimestamp();
}

public function __sleep()
public function __serialize(): array
{
// Stream/Resource can't be serialized... So we copy the content into an implementation of `Psr\Http\Message\StreamInterface`
if ($this->response !== null) {
$responseBody = (string)$this->response->getBody();
$this->response = $this->response->withBody(
new PumpStream(
new BodyStore($responseBody),
[
'size' => mb_strlen($responseBody),
]
)
);
}
return [
'request' => self::toSerializeableMessage($this->request),
'response' => $this->response !== null ? self::toSerializeableMessage($this->response) : null,
'staleAt' => $this->staleAt,
'staleIfErrorTo' => $this->staleIfErrorTo,
'staleWhileRevalidateTo' => $this->staleWhileRevalidateTo,
'dateCreated' => $this->dateCreated,
'timestampStale' => $this->timestampStale,
];
}

public function __unserialize(array $data): void
{
$this->request = self::restoreStreamBody($data['request']);
$this->response = $data['response'] !== null ? self::restoreStreamBody($data['response']) : null;
$this->staleAt = $data['staleAt'];
$this->staleIfErrorTo = $data['staleIfErrorTo'];
$this->staleWhileRevalidateTo = $data['staleWhileRevalidateTo'];
$this->dateCreated = $data['dateCreated'];
$this->timestampStale = $data['timestampStale'];
}

/**
* Stream/Resource can't be serialized... So we copy the content into an implementation of `Psr\Http\Message\StreamInterface`
*
* @template T of MessageInterface
*
* @param T $message
* @return T
*/
private static function toSerializeableMessage(MessageInterface $message): MessageInterface
{
$bodyString = (string)$message->getBody();

$requestBody = (string)$this->request->getBody();
$this->request = $this->request->withBody(
return $message->withBody(
new PumpStream(
new BodyStore($requestBody),
new BodyStore($bodyString),
[
'size' => mb_strlen($requestBody)
'size' => mb_strlen($bodyString),
]
)
);
}

return array_keys(get_object_vars($this));
/**
* @template T of MessageInterface
*
* @param T $message
* @return T
*/
private static function restoreStreamBody(MessageInterface $message): MessageInterface
{
return $message->withBody(
\GuzzleHttp\Psr7\Utils::streamFor((string) $message->getBody())
);
}

public function __wakeup()
public function serialize()
{
// We re-create the stream of the response
if ($this->response !== null) {
$this->response = $this->response
->withBody(
\GuzzleHttp\Psr7\Utils::streamFor((string) $this->response->getBody())
);
}
$this->request = $this->request
->withBody(
\GuzzleHttp\Psr7\Utils::streamFor((string) $this->request->getBody())
);
return serialize($this->__serialize());
}

public function unserialize($data)
{
$this->__unserialize(unserialize($data));
}
}
23 changes: 23 additions & 0 deletions tests/CacheEntryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,29 @@ public function testCacheEntryShouldBeSerializableWithIgBinaryWithoutWarning()
}
}

public function testSerializationShouldNotMutateCacheEntry()
{
$request = new Request(
'GET',
'test.local',
[],
'Sample body' // Always include a body in the request to be sure there is a stream in it
);
$response = new Response(
200, [
'Cache-Control' => 'max-age=60',
],
'Test content'
);
$cacheEntry = new CacheEntry($request, $response, $this->makeDateTimeOffset(10));

$originalCacheEntry = clone $cacheEntry;

serialize($cacheEntry);

$this->assertEquals($cacheEntry, $originalCacheEntry);
}

private function setResponseHeader($name, $value)
{
$this->responseHeaders[$name] = [$value];
Expand Down

0 comments on commit 0e12dcc

Please sign in to comment.