Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .github/workflows/php-cs-fixer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v2
with:
ref: ${{ github.head_ref }}
token: ${{ secrets.PHP_CS_FIXER }}
uses: actions/checkout@v3
- name: Run PHP CS Fixer
uses: docker://oskarstark/php-cs-fixer-ga
with:
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.13",
"pestphp/pest": "^1.21.2",
"pestphp/pest": "^2.3",
"spatie/ray": "^1.34.2",
"league/flysystem": "^3.12.2",
"orchestra/testbench": "^8.0",
Expand Down
28 changes: 12 additions & 16 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
bootstrap="vendor/autoload.php"
colors="true"
>
<testsuites>
<testsuite name="Test Suite">
<directory suffix="Test.php">./tests</directory>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
<directory suffix=".php">./app</directory>
<directory suffix=".php">./src</directory>
</include>
</coverage>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd" bootstrap="vendor/autoload.php" colors="true" cacheDirectory=".phpunit.cache">
<testsuites>
<testsuite name="Test Suite">
<directory suffix="Test.php">./tests</directory>
</testsuite>
</testsuites>
<coverage>
<include>
<directory suffix=".php">./app</directory>
<directory suffix=".php">./src</directory>
</include>
</coverage>
</phpunit>
4 changes: 2 additions & 2 deletions src/Http/Middleware/CacheMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public function __construct(
protected Driver $driver,
protected int $ttl,
protected ?string $cacheKey,
protected bool $invalidate = false,
protected bool $invalidate = false,
) {
//
}
Expand All @@ -53,7 +53,7 @@ public function __invoke(PendingRequest $pendingRequest): ?SimulatedResponsePayl
// the SimulatedResponsePayload here.

if ($this->invalidate === false && $cachedResponse->hasNotExpired()) {
$pendingRequest->middleware()->onResponse(fn (Response $response) => $response->setCached(true));
$pendingRequest->middleware()->onResponse(fn (Response $response) => $response->setCached(true), true);

return $cachedResponse->getSimulatedResponsePayload();
}
Expand Down
15 changes: 10 additions & 5 deletions src/Traits/HasCaching.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,17 @@ public function bootHasCaching(PendingRequest $pendingRequest): void
? $request->cacheExpiryInSeconds()
: $connector->cacheExpiryInSeconds();

// Register a request middleware which wil handle the caching and recording
// of real responses for caching.
// Register a request middleware which wil handle the caching
// and recording of real responses for caching.

$pendingRequest->middleware()->onRequest(
callable: new CacheMiddleware($cacheDriver, $cacheExpiryInSeconds, $this->cacheKey($pendingRequest), $this->invalidateCache),
);
$pendingRequest->middleware()->onRequest(function (PendingRequest $middlewarePendingRequest) use ($cacheDriver, $cacheExpiryInSeconds) {
// We'll call the cache middleware invokable class with the $middlewarePendingRequest
// because this $pendingRequest has everything loaded, unlike the instance that
// the plugin is provided. This allows us to have access to body and merged
// properties.

return call_user_func(new CacheMiddleware($cacheDriver, $cacheExpiryInSeconds, $this->cacheKey($middlewarePendingRequest), $this->invalidateCache), $middlewarePendingRequest);
});
}

/**
Expand Down
32 changes: 32 additions & 0 deletions tests/Feature/CacheTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Saloon\CachePlugin\Tests\Fixtures\Connectors\CachedConnector;
use Saloon\CachePlugin\Tests\Fixtures\Requests\CachedPostRequest;
use Saloon\CachePlugin\Tests\Fixtures\Requests\CachedUserRequest;
use Saloon\CachePlugin\Tests\Fixtures\Requests\BodyCacheKeyRequest;
use Saloon\CachePlugin\Tests\Fixtures\Requests\CachedConnectorRequest;
use Saloon\CachePlugin\Tests\Fixtures\Requests\AllowedCachedPostRequest;
use Saloon\CachePlugin\Tests\Fixtures\Requests\CustomKeyCachedUserRequest;
Expand Down Expand Up @@ -186,6 +187,37 @@
expect($responseC->isCached())->toBeFalse();
});

test('body can be used in the cache key', function () {
$mockClient = new MockClient([
MockResponse::make(['name' => 'Sam']),
MockResponse::make(['name' => 'Gareth']),
]);

$requestA = new BodyCacheKeyRequest;
$requestA->body()->set([
'name' => 'Sam',
'expiry' => '10 hours',
]);

$responseA = TestConnector::make()->send($requestA, $mockClient);

expect($responseA->isCached())->toBeFalse();
expect($responseA->json())->toEqual(['name' => 'Sam']);
expect($responseA->status())->toEqual(200);

$requestB = new BodyCacheKeyRequest;
$requestB->body()->set([
'name' => 'Sam',
'expiry' => '10 hours',
]);

$responseB = TestConnector::make()->send($requestB, $mockClient);

expect($responseB->isCached())->toBeTrue();
expect($responseB->json())->toEqual(['name' => 'Sam']);
expect($responseB->status())->toEqual(200);
});

test('you will not receive a cached response if the response has expired', function () {
$mockClient = new MockClient([
MockResponse::make(['name' => 'Sam']),
Expand Down
48 changes: 48 additions & 0 deletions tests/Fixtures/Requests/BodyCacheKeyRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

declare(strict_types=1);

namespace Saloon\CachePlugin\Tests\Fixtures\Requests;

use Saloon\Enums\Method;
use Saloon\Http\Request;
use League\Flysystem\Filesystem;
use Saloon\Contracts\Body\HasBody;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Contracts\PendingRequest;
use Saloon\CachePlugin\Contracts\Driver;
use Saloon\CachePlugin\Traits\HasCaching;
use Saloon\CachePlugin\Contracts\Cacheable;
use Saloon\CachePlugin\Drivers\FlysystemDriver;
use League\Flysystem\Local\LocalFilesystemAdapter;
use Saloon\CachePlugin\Tests\Fixtures\Connectors\TestConnector;

class BodyCacheKeyRequest extends Request implements Cacheable, HasBody
{
use HasCaching;
use HasJsonBody;

protected ?string $connector = TestConnector::class;

protected Method $method = Method::GET;

public function resolveEndpoint(): string
{
return '/user';
}

public function resolveCacheDriver(): Driver
{
return new FlysystemDriver(new Filesystem(new LocalFilesystemAdapter(cachePath())));
}

public function cacheExpiryInSeconds(): int
{
return 60;
}

protected function cacheKey(PendingRequest $pendingRequest): ?string
{
return (string)$pendingRequest->body()->all();
}
}