Skip to content

Commit

Permalink
Merge pull request #274 from boesing/docs/v4
Browse files Browse the repository at this point in the history
Documentation for v4.0.0 including migration guide
  • Loading branch information
boesing committed May 8, 2024
2 parents d4b8cc0 + f173c27 commit 5fc9681
Show file tree
Hide file tree
Showing 21 changed files with 2,523 additions and 20 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ $storage->setItem('foo', 'bar');

We provide scripts for benchmarking laminas-cache using the
[PHPBench](https://github.com/phpbench/phpbench) framework; these can be
found in the `benchmark/` directory.
found in the `benchmark/` directory of each storage adapter.

To execute the benchmarks you can run the following command:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
# Usage in a laminas-mvc Application

The following example shows _one_ potential use case of laminas-cache within a laminas-mvc based application.
The example uses a module, a controller and shows the resolving of dependencies of the controller by configuration.

## Preparation

Before starting, make sure laminas-cache is [installed and configured](../installation.md).

> MISSING: **Installation Requirements**
> laminas-cache is shipped without a specific cache adapter to allow free choice of storage backends and their dependencies.
> So make sure that the required adapters are installed.
>
> The following example used the [filesystem adapter of laminas-cache](../storage/adapter.md#filesystem-adapter):
>
> ```bash
> $ composer require laminas/laminas-cache-storage-adapter-filesystem
> ```
## Configure Cache

To configure the cache in a laminas-mvc based application, use either application or module configuration (such as `config/autoload/*.global.php` or `module/Application/config/module.config.php`, respectively), and define the configuration key `caches`.

In this example, the global configuration is used and a separate file is created for the cache configuration.
Create a configuration file with name like `config/autoload/cache.global.php` and it will [automatically be included](https://docs.laminas.dev/tutorials/advanced-config/#environment-specific-application-configuration):

```php
return [
'caches' => [
'default-cache' => [
'adapter' => Laminas\Cache\Storage\Adapter\Filesystem::class,
'options' => [
'cache_dir' => __DIR__ . '/../../data/cache',
],
],
],
];
```

The factory `Laminas\Cache\Service\StorageCacheAbstractServiceFactory` uses the configuration, searches for the configuration key `caches` and creates the storage adapters using the discovered configuration.

## Create Controller

[Create a controller class](https://docs.laminas.dev/laminas-mvc/quick-start/#create-a-controller) and inject the cache with the interface for all cache storage adapters via the constructor, e.g. `module/Application/Controller/IndexController.php`:

```php
namespace Application\Controller;

use Laminas\Cache\Storage\StorageInterface;
use Laminas\Mvc\Controller\AbstractActionController;

final class IndexController extends AbstractActionController
{
public function __construct(
private readonly StorageInterface $cache
) {}

public function indexAction(): array
{
if (! $this->cache->hasItem('example')) {
$this->cache->addItem('example', 'value');
}

echo $this->cache->getItem('example') // value;

// …

return [];
}
}
```

## Register Controller

To [register the controller](https://docs.laminas.dev/laminas-mvc/quick-start/#create-a-route) for the application, extend the configuration of the module.
Add the following lines to the module configuration file, e.g. `module/Application/config/module.config.php`:

<pre class="language-php" data-line="3,8"><code>
namespace Application;

use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;

return [
'controllers' => [
'factories' => [
Controller\IndexController::class => ConfigAbstractFactory::class,
],
],
// …
];
</code></pre>

The example uses the [config factory from laminas-servicemanager](https://docs.laminas.dev/laminas-servicemanager/config-abstract-factory/) which allows any string to be used to fetch a service from the application service container, like the name of the configured cache: `default-cache`.

This means that the factory [searches for an appropriate configuration](https://docs.laminas.dev/laminas-servicemanager/config-abstract-factory/#configuration) to create the controller and to resolve the constructor dependencies for the controller class.

### Add Factory Configuration For Controller

Extend the module configuration file to add the configuration for the controller.
Use the name of the cache (`default-cache`), which was previously defined in the configuration of the caches, to retrieve the related cache storage instance:

<pre class="language-php" data-line="11-15"><code>
namespace Application;

use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;

return [
'controllers' => [
'factories' => [
Controller\IndexController::class => ConfigAbstractFactory::class,
],
],
ConfigAbstractFactory::class => [
Controller\IndexController::class => [
'default-cache',
],
],
// …
];
</code></pre>

## Using Multiple Caches

The use more than one cache backend, the factory `Laminas\Cache\Service\StorageCacheAbstractServiceFactory` allows to define multiple cache storages.

Extend the cache configuration in `config/autoload/cache.global.php` and add more cache adapters:

<pre class="language-php" data-line="9-14"><code>
return [
'caches' => [
'default-cache' => [
'adapter' => Laminas\Cache\Storage\Adapter\Filesystem::class,
'options' => [
'cache_dir' => __DIR__ . '/../../data/cache',
],
],
'secondary-cache' => [
'adapter' => Laminas\Cache\Storage\Adapter\Memory::class,
],
'dummy-cache' => [
'adapter' => Laminas\Cache\Storage\Adapter\BlackHole::class,
],
],
];
</code></pre>

MISSING: **Installation Requirements**
Make sure that the [used storage adapters are installed](#preparation):
```bash
$ composer require laminas/laminas-cache-storage-adapter-memory laminas/laminas-cache-storage-adapter-blackhole
```

### Change Used Adapter for Controller

To use a different cache adapter for the controller, change the related module configuration and use one of the previously defined names:

<pre class="language-php" data-line="13"><code>
namespace Application;

use Laminas\ServiceManager\AbstractFactory\ConfigAbstractFactory;

return [
'controllers' => [
'factories' => [
Controller\IndexController::class => ConfigAbstractFactory::class,
],
],
ConfigAbstractFactory::class => [
Controller\IndexController::class => [
'dummy-cache',
],
],
// …
];
</code></pre>

## Learn More

- [Storage Adapters](../storage/adapter.md)
- [Environment-Specific Application Configuration](https://docs.laminas.dev/tutorials/advanced-config/#environment-specific-application-configuration)
- [Configuration-based Abstract Factory](https://docs.laminas.dev/laminas-servicemanager/config-abstract-factory/)
5 changes: 5 additions & 0 deletions docs/book/v4/installation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# This Is Only a Placeholder

The content of this page can be found under:

https://github.com/laminas/documentation-theme/blob/master/theme/pages/installation.html
45 changes: 45 additions & 0 deletions docs/book/v4/migration/to-version-4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Migration to Version 4.0

Finally, native types **everywhere**. With v4.0, `laminas-cache` depends on `laminas-servicemanager` v4 which already introduced full native types and thus, cache now has native types as well.
Along with these changes, we also decided to remove and/or enhance some features to make the usage of this component more user-friendly.
So instead of working with metadata arrays, a new `MetadataCapableInterface` was introduced which provides a generic interface for storage adapters to tell both IDEs and static analysers to understand what metadata instances are returned for which storage adapter.
This allows per-storage Metadata which can differ depending on the storage being used.

## Checklist

1. Ensure you are on latest `laminas/laminas-cache` v3
2. Ensure you are on latest `laminas/laminas-cache-storage-adapter-*` version (might differ)
3. Verify that you are **not** using one of the following methods
1. `StorageInterface#incrementItem` (no replacement available, should be implemented in userland code)
2. `StorageInterface#incrementItems` (no replacement available, should be implemented in userland code)
3. `StorageInterface#decrementItem` (no replacement available, should be implemented in userland code)
4. `StorageInterface#decrementItems` (no replacement available, should be implemented in userland code)
4. Verify that you are **not** using `supportedMetadata` capability (use `MetadataCapableInterface#getMetadata` instead)
5. Verify that you are **not** using `KeyListIterator` with mode `CURRENT_AS_METADATA` (use the returned `key` instead and pass it to the `MetadataCapable` storage adapter (**NOTE: not all adapters do implement `MetadataCapableInterface`**)
6. If you use the `Serializer` plugin
1. Verify that if you pass a `string` as `serializer` option, you do not directly depend on the return value of `PluginOptions#getSerializer` (method will return `string` instead of instantiating a new `SerializerInterface` instance). The plugin itself can still handle `string` and an instance of `SerializerInterface` as in previous versions
7. If you provide own plugins, storage adapters, pattern, you have to upgrade to v4 and update all method/argument/property (return-) types according to the updated versions. Check out [rector](https://github.com/rectorphp/rector) which can help with this kind of migration
8. If you are handling `Laminas\Cache\Exception\MissingKeyException`, you can remove that code as the exception does not exist anymore
9. Check if you use `ObjectCache` pattern, that your code does not expect an instance of `CallbackCache` to be passed

## New Features

- Every adapter which supports `metadata` now implements `MetadataCapableInterface` and provides a dedicated object containing all the metadata values it supports
- Adds support for `psr/cache` and `psr/simple-cache` v2 & v3

## Removed Classes

- `Laminas\Cache\Exception\MissingKeyException`

## Breaking Changes

- `AbstractAdapter` and `StorageInterface` are not aware of the methods `getMetadata` anymore. These were moved to the new `MetadataCapableInterface`
- `Capabilities` do not provide `supportedMetadata` anymore. The supported metadata is tied to the used storage adapter and thus, was already requiring projects to explicitly know the exact implementation of the cache backend in case of using these metadatas anyway
- `KeyListIterator` and the corresponding `IteratorInterface` does not provide the `mode` `CURRENT_AS_METADATA` anymore
- `PluginOptions#getSerializer` does not create a serializer anymore if a `string` option was passed, instead, the `string` is returned
- Increment and decrement feature was removed from `StorageInterface`, so there is no more `StorageInterface#incrementItem`, `StorageInterface#decrementItem`, `StorageInterface#decrementItems` and `StorageInterface#incrementItems`
- this also removes `incrementItem`, `incrementItems`, `decrementItem`, `derementItems` events (`pre`, `post` and `exception`)
- Every method now has native return types
- Every property now has native types
- Every method argument now has native types
- `ObjectCache` does not inherit the `CallbackCache` pattern anymore
87 changes: 87 additions & 0 deletions docs/book/v4/pattern/callback-cache.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# CallbackCache

The callback cache pattern caches the results of arbitrary PHP callables.

## Quick Start

```php
use Laminas\Cache\Pattern\CallbackCache;
use Laminas\Cache\Pattern\PatternOptions;

// Or the equivalent manual instantiation:
$callbackCache = new CallbackCache(
$storage,
new PatternOptions([
'cache_output' => true,
])
);
```

> ### Storage Adapter
>
> The `$storage` adapter can be any adapter which implements the `StorageInterface`. Check out the [Pattern Quick Start](./intro.md#quick-start)-Section for a standard adapter which can be used here.
## Configuration Options

| Option | Data Type | Default Value | Description |
|----------------|---------------------------------------------------------|---------------|------------------------------------------------------------------|
| `storage` | `string\|array\|Laminas\Cache\Storage\StorageInterface` | none | **deprecated** Adapter used for reading and writing cached data. |
| `cache_output` | `bool` | `true` | Whether or not to cache callback output. |

## Examples

### Instantiating the Callback Cache Pattern

```php
use Laminas\Cache\Pattern\CallbackCache;

$callbackCache = new CallbackCache($storage);
```

## Available Methods

In addition to the methods defined in the `PatternInterface` and the `StorageCapableInterface`, this
implementation provides the following methods.

```php
namespace Laminas\Cache\Pattern;

use Laminas\Cache\Exception;

class CallbackCache extends AbstractStorageCapablePattern
{
/**
* Call the specified callback or get the result from cache
*
* @param callable $callback A valid callback
* @param array $args Callback arguments
* @return mixed Result
* @throws Exception\RuntimeException if invalid cached data
* @throws \Exception
*/
public function call(callable $callback, array $args = []): mixed;

/**
* Intercept method overloading; proxies to call()
*
* @param callable-string $function Function name to call
* @param array $args Function arguments
* @return mixed
* @throws Exception\RuntimeException
* @throws \Exception
*/
public function __call(string $function, array $args): mixed;

/**
* Generate a unique key in base of a key representing the callback part
* and a key representing the arguments part.
*
* @param callable $callback A valid callback
* @param array $args Callback arguments
* @return non-empty-string
* @throws Exception\RuntimeException
* @throws Exception\InvalidArgumentException
*/
public function generateKey(callable $callback, array $args = []): string;
}
```

0 comments on commit 5fc9681

Please sign in to comment.