Skip to content

Commit

Permalink
[Cache] New Component (#112)
Browse files Browse the repository at this point in the history
- [x] php-cs-fixer
- [x] Documentation
- [x] psalm
  • Loading branch information
JoshuaEstes authored Nov 7, 2023
1 parent e645565 commit 7656a53
Show file tree
Hide file tree
Showing 35 changed files with 2,019 additions and 10 deletions.
4 changes: 4 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ Bard:
- docs/bard/*
- src/SonsOfPHP/Bard/*

Cache:
- docs/components/cache/*
- src/SonsOfPHP/**/Cache/*

Clock:
- docs/components/clock/*
- src/SonsOfPHP/Component/Clock/*
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
with:
php-version: ${{ matrix.php-version }}
coverage: xdebug
extensions: apcu
- name: Cache Composer Packages
id: composer-cache
uses: actions/cache@v3
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ jobs:
with:
php-version: ${{ matrix.php-version }}
coverage: none
extensions: apcu
- name: Cache Composer Packages
id: composer-cache
uses: actions/cache@v3
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Examples:
* [PR #59](https://github.com/SonsOfPHP/sonsofphp/pull/59) Added new HttpMessage component
* [PR #59](https://github.com/SonsOfPHP/sonsofphp/pull/59) Added new HttpFactory component
* [PR #70](https://github.com/SonsOfPHP/sonsofphp/pull/70) Added new Core contract
* [PR #112](https://github.com/SonsOfPHP/sonsofphp/pull/112) [Cache] Added new component

## [0.3.8]

Expand Down
20 changes: 18 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,16 @@ purge: # Purge vendor and lock files
rm -rf vendor/ src/SonsOfPHP/Bridge/*/vendor/ src/SonsOfPHP/Bridge/*/composer.lock
rm -rf vendor/ src/SonsOfPHP/Bundle/*/vendor/ src/SonsOfPHP/Bundle/*/composer.lock
rm -rf vendor/ src/SonsOfPHP/Component/*/vendor/ src/SonsOfPHP/Component/*/composer.lock
rm -rf vendor/ src/SonsOfPHP/Contract/*/vendor/ src/SonsOfPHP/Contract/*/composer.lock

test: ## Run PHPUnit Tests
XDEBUG_MODE=off $(PHP) -dxdebug.mode=off $(PHPUNIT) --order-by=defects
XDEBUG_MODE=off \
$(PHP) \
-dxdebug.mode=off \
-dapc.enable_cli=1 \
$(PHPUNIT) \
--cache-result \
--order-by=defects

phpunit: test

Expand All @@ -55,7 +62,16 @@ lint-php: # lint php files
find src -name "*.php" -not -path "src/**/vendor/*" | xargs -I{} $(PHP) -l '{}'

coverage: ## Build Code Coverage Report
XDEBUG_MODE=coverage $(PHP) -dxdebug.mode=coverage $(PHPUNIT) --coverage-html $(COVERAGE_DIR)
XDEBUG_MODE=coverage \
$(PHP) \
-dxdebug.mode=coverage \
-dapc.enable_cli=1 \
$(PHPUNIT) \
--cache-result \
--coverage-html $(COVERAGE_DIR)

coverage-cache:
XDEBUG_MODE=coverage $(PHP) -dxdebug.mode=coverage $(PHPUNIT) --testsuite cache --coverage-html $(COVERAGE_DIR)

coverage-clock:
XDEBUG_MODE=coverage $(PHP) -dxdebug.mode=coverage $(PHPUNIT) --testsuite clock --coverage-html $(COVERAGE_DIR)
Expand Down
4 changes: 4 additions & 0 deletions bard.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
"path": "src/SonsOfPHP/Bard",
"repository": "git@github.com:SonsOfPHP/bard.git"
},
{
"path": "src/SonsOfPHP/Component/Cache",
"repository": "git@github.com:SonsOfPHP/cache.git"
},
{
"path": "src/SonsOfPHP/Component/Clock",
"repository": "git@github.com:SonsOfPHP/clock.git"
Expand Down
26 changes: 18 additions & 8 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
"support": {
"issues": "https://github.com/SonsOfPHP/sonsofphp/issues",
"forum": "https://github.com/orgs/SonsOfPHP/discussions",
"docs": "https://docs.sonsofphp.com",
"chat": "https://discord.gg/sdVxNhFqND"
"docs": "https://docs.sonsofphp.com"
},
"funding": [
{
Expand All @@ -36,7 +35,9 @@
"psr/event-dispatcher-implementation": "1.0",
"psr/clock-implementation": "1.0",
"psr/http-message-implementation": "^1.0",
"psr/http-factory-implementation": "^1.0"
"psr/http-factory-implementation": "^1.0",
"psr/cache-implementation": "^3.0",
"psr/simple-cache-implementation": "^3.0"
},
"require": {
"php": ">=8.1",
Expand All @@ -55,7 +56,9 @@
"symfony/messenger": "^5|^6",
"psr/clock": "^1.0",
"psr/http-message": "^1.0",
"psr/http-factory": "^1.0"
"psr/http-factory": "^1.0",
"psr/cache": "^3.0",
"psr/simple-cache": "^3.0"
},
"replace": {
"sonsofphp/bard": "self.version",
Expand All @@ -73,11 +76,14 @@
"sonsofphp/cqrs-bundle": "self.version",
"sonsofphp/filesystem": "self.version",
"sonsofphp/http-message": "self.version",
"sonsofphp/http-factory": "self.version"
"sonsofphp/http-factory": "self.version",
"sonsofphp/core-contract": "self.version",
"sonsofphp/cache": "self.version"
},
"autoload": {
"psr-4": {
"SonsOfPHP\\Bard\\": "src/SonsOfPHP/Bard/src",
"SonsOfPHP\\Component\\Cache\\": "src/SonsOfPHP/Component/Cache",
"SonsOfPHP\\Component\\Clock\\": "src/SonsOfPHP/Component/Clock",
"SonsOfPHP\\Component\\Cqrs\\": "src/SonsOfPHP/Component/Cqrs",
"SonsOfPHP\\Bundle\\Cqrs\\": "src/SonsOfPHP/Bundle/Cqrs",
Expand All @@ -92,10 +98,12 @@
"SonsOfPHP\\Component\\HttpMessage\\": "src/SonsOfPHP/Component/HttpMessage",
"SonsOfPHP\\Component\\Json\\": "src/SonsOfPHP/Component/Json",
"SonsOfPHP\\Component\\Money\\": "src/SonsOfPHP/Component/Money",
"SonsOfPHP\\Component\\Version\\": "src/SonsOfPHP/Component/Version"
"SonsOfPHP\\Component\\Version\\": "src/SonsOfPHP/Component/Version",
"SonsOfPHP\\Contract\\Core\\": "src/SonsOfPHP/Contract/Core"
},
"exclude-from-classmap": [
"src/SonsOfPHP/Bard/Tests",
"src/SonsOfPHP/Component/Cache/Tests",
"src/SonsOfPHP/Component/Clock/Tests",
"src/SonsOfPHP/Component/Cqrs/Tests",
"src/SonsOfPHP/Bundle/Cqrs/Tests",
Expand All @@ -110,7 +118,8 @@
"src/SonsOfPHP/Component/HttpMessage/Tests",
"src/SonsOfPHP/Component/Json/Tests",
"src/SonsOfPHP/Component/Money/Tests",
"src/SonsOfPHP/Component/Version/Tests"
"src/SonsOfPHP/Component/Version/Tests",
"src/SonsOfPHP/Contract/Core/Tests"
]
},
"extra": {
Expand All @@ -124,7 +133,8 @@
"symfony/serializer": "^5|^6",
"symfony/phpunit-bridge": "^6",
"symfony/error-handler": "^6",
"symfony/messenger": "^5|^6"
"symfony/messenger": "^5|^6",
"phpunit/phpunit": "^10.4"
},
"autoload-dev": {
"psr-4": {
Expand Down
66 changes: 66 additions & 0 deletions docs/components/cache/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
title: Cache - Overview
---

Used for cache stuff

## Installation

```shell
composer require sonsofphp/cache
```

### PSR-16 - Simple Cache

To add support for PSR-16 Simple Cache, require the PSR.

```shell
composer require psr/simple-cache
```

## Usage

```php
<?php

use SonsOfPHP\Component\Cache\Adapter\ApcuAdapter;

$pool = new ApcuAdapter();
```

All Adapters implement `Psr\Cache\CacheItemPoolInterface`

### PSR-16 Simple Cache Wrapper

```php
<?php

use SonsOfPHP\Component\Cache\Adapter\ApcuAdapter;
use SonsOfPHP\Component\Cache\SimpleCache;

$pool = new ApcuAdapter();
$cache = new SimpleCache($pool);
```

`SimpleCache` implements `Psr\SimpleCache\CacheInterface`.

### Setting up a multi layer cache

```php
<?php

use SonsOfPHP\Component\Cache\Adapter\ArrayAdapter;
use SonsOfPHP\Component\Cache\Adapter\ApcuAdapter;
use SonsOfPHP\Component\Cache\Adapter\ChainAdapter;

$pool = new ChainAdapter([
new ArrayAdapter(),
new ApcuAdapter(),
]);
```

The `ChainAdapter` will read from all pools and return the first result it
finds. So in the above example, if the cache item is not found in
`ArrayAdapter`, it will look for it in the `ApcuAdapter` pool.

The `ChainAdapter` will also write to and delete from all pools.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ nav:
- bard/index.md
- Components:
- components/index.md
- Cache: components/clock/index.md
- Clock: components/clock/index.md
- CQRS:
- components/cqrs/index.md
Expand Down
4 changes: 4 additions & 0 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
<!--<directory>src/SonsOfPHP/Bard/src/Tests</directory>-->
</testsuite>

<testsuite name="cache">
<directory>src/SonsOfPHP/Component/Clock/Tests</directory>
</testsuite>

<testsuite name="clock">
<directory>src/SonsOfPHP/Component/Clock/Tests</directory>
</testsuite>
Expand Down
4 changes: 4 additions & 0 deletions src/SonsOfPHP/Component/Cache/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/Tests export-ignore
/phpunit.xml.dist export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
3 changes: 3 additions & 0 deletions src/SonsOfPHP/Component/Cache/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
composer.lock
phpunit.xml
vendor/
14 changes: 14 additions & 0 deletions src/SonsOfPHP/Component/Cache/Adapter/AdapterInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace SonsOfPHP\Component\Cache\Adapter;

use Psr\Cache\CacheItemPoolInterface;

/**
* All Adapters MUST implement this interface
*
* @author Joshua Estes <joshua@sonsofphp.com>
*/
interface AdapterInterface extends CacheItemPoolInterface {}
122 changes: 122 additions & 0 deletions src/SonsOfPHP/Component/Cache/Adapter/ApcuAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?php

declare(strict_types=1);

namespace SonsOfPHP\Component\Cache\Adapter;

use SonsOfPHP\Component\Cache\CacheItem;
use Psr\Cache\CacheItemInterface;
use SonsOfPHP\Component\Cache\Exception\CacheException;

/**
* @author Joshua Estes <joshua@sonsofphp.com>
*/
class ApcuAdapter implements AdapterInterface
{
private array $deferred = [];

public function __construct()
{
if (!extension_loaded('apcu') || !filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOL) || false === apcu_enabled()) {
throw new CacheException('APCu extension is required.');
}
}

/**
* {@inheritdoc}
*/
public function getItem(string $key): CacheItemInterface
{
if ($this->hasItem($key)) {
return (new CacheItem($key, true))->set(apcu_fetch($key));
}

return new CacheItem($key, false);
}

/**
* {@inheritdoc}
*/
public function getItems(array $keys = []): iterable
{
foreach ($keys as $key) {
yield $key => $this->getItem($key);
}
}

/**
* {@inheritdoc}
*/
public function hasItem(string $key): bool
{
CacheItem::validateKey($key);

return apcu_exists($key);
}

/**
* {@inheritdoc}
*/
public function clear(): bool
{
return apcu_clear_cache();
}

/**
* {@inheritdoc}
*/
public function deleteItem(string $key): bool
{
CacheItem::validateKey($key);

return apcu_delete($key);
}

/**
* {@inheritdoc}
*/
public function deleteItems(array $keys): bool
{
$ret = true;
foreach ($keys as $key) {
if (!$this->deleteItem($key)) {
$ret = false;
}
}

return $ret;
}

/**
* {@inheritdoc}
*/
public function save(CacheItemInterface $item): bool
{
$this->saveDeferred($item);

return $this->commit();
}

/**
* {@inheritdoc}
*/
public function saveDeferred(CacheItemInterface $item): bool
{
$this->deferred[$item->getKey()] = $item;

return true;
}

/**
* {@inheritdoc}
*/
public function commit(): bool
{
foreach ($this->deferred as $key => $item) {
apcu_store($key, $item->get(), 0);
}
$this->deferred = [];

return true;
}
}
Loading

0 comments on commit 7656a53

Please sign in to comment.