Giter Club home page Giter Club logo

transient-cache's Introduction

WP Transient Cache

Build Status Latest Stable Version Latest Unstable Version

A fully compliant PSR-16 wrapper for WP transients.

Details

A common means of caching values in WordPress is by using transients. However, this approach suffers from several problems:

  1. Coupling to WordPress. You can't just suddenly substitute the caching mechanism you are using for another mechanism, and everything still works.
  2. No namespacing. All transients live in the same namespace, and independent consumers cannot reliably use arbitrary keys without the risk of possible conflict.
  3. No true modularity. Due to the above, if your application is modular, it cannot decide which caching mechanisms to use for what, because that would have already been decided by your modules.
  4. Missing features. For example, it is not possible to clear all values related to a particular thing in one go. Exceptions are missing too, and you have to rely on ambiguous return values.

This standards-compliant wrapper addresses all of the above. It is a true PSR-16 cache, which uses WordPress transients as storage. Exceptions are raised, interfaces implemented, and true false-negative detection is in place. Each instance of the cache pool is logically independent from other instances, provided that it is given a unique name. The application is once again in control, and modules that use cache can become platform agnostic.

Compatibility

  • CachePool and CachePoolFactory offer best-practices error handling, throwing meaningful exceptions when something goes wrong. This violates PSR-16, but allows you to know what is failing.
  • SilentPool and SilentPoolFactory offer PSR-16 compatibility at the cost of error handling, hiding exceptions, and returning standards-compatible values. This complies with PSR-16, but at the cost of clarity and verbosity.

Usage

/*
 * Set up the factory - usually in a service definition
 */
use wpdb;
use Psr\SimpleCache\CacheInterface;
use WpOop\TransientCache\CachePoolFactory;
use WpOop\TransientCache\SilentPoolFactory;

/* @var $wpdb wpdb */
$factory = new CachePoolFactory($wpdb);
// Optionally hide exceptions for PSR-16 compatibility
$factory = new SilentPoolFactory($factory); // Optional, and not recommended for testing environments!

/*
 * Create cache pools - usually somewhere else
 */
// Same wpdb instance used, default value generated automatically
$pool1 = $factory->createCachePool('client-access-tokens');
$pool2 = $factory->createCachePool('remote-api-responses');
$pool3 = $factory->createCachePool('other-stuff');

/*
 * Use cache pools - usually injected into a client class
 */

// No collision of key between different pools
$pool1->set('123', $someToken);
$pool2->set('123', $someResponseBody);
$pool3->set('123', false);

// Depend on an interop standard
(function (CacheInterface $cache) {
    // False negative detection: correctly determines that the value is actually `false`
    $cache->has('123'); // true
    $cache->get('123', uniqid('default')) === false; // true
})($pool3);

// Clear all values within a pool
$pool2->clear();
$pool2->has('123'); // false
$pool1->has('123'); // true

Limitations

Key Length

Due to the way the underlying backend (the WordPress transients via options) works, the combined length of the pool name and cache key MUST NOT exceed a 171 char limit. This is because (at least in WP 5.0+) the length of the option_name field of the options table is 191 chars, and transients require the longest prefix of _transient_timeout_ to the option name, which together with the 1-char separator is 20 chars. Using anything greater than this length will result in potentially devastating behaviour described in Trac #15058.

In any case, the general recommendation is that consumers SHOULD NOT use cache keys longer than 64 chars, as this is the minimal length required for support by the PSR-16 spec. Using anything longer than that will cause consumers to become dependent on implementation detail, which breaks interoperability. Given that, the cache pool name SHOULD NOT exceed 107 chars.

Value Length

The storage backend (WP options) declares the corresponding field to be of type LONGTEXT, which allows up to 4 GB (232) of data. This is therefore the limit on cache values.

transient-cache's People

Contributors

brianhenryie avatar mecha avatar szepeviktor avatar xedinunknown avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

transient-cache's Issues

Import global WP function

e.g. in CachePool

use function set_transient;
use function delete_transient;
use function get_transient;
use function get_option;

What do you think about it?

Default TTL in CachePool

It would be great if the CachePool was aware of a default TTL, to avoid having to inject the pool instance and a TTL config value into all dependents.

At the moment, the CachePool defaults to 0 when no TTL is given in set(). This proposal would see that 0 literal changed with the instance's default TTL.

Wrong Package License

The Problem

This package is licensed under MIT. However, it uses some WordPress functions, such as set_transient(). According to GPL, anything that derives from GPL must be GPL. And WordPress is GPL...

Suggested Solution

Change package license to GPL-2.0-or-later.

Exceptions Not PSR-Compliant

Hello @XedinUnknown!

What a release!

 ------ -------------------------------------------------------------------------------------------------------------
  Line   CachePool.php
 ------ -------------------------------------------------------------------------------------------------------------
  112    Method WpOop\TransientCache\CachePool::set() should return bool but return statement is missing.
  126    Method WpOop\TransientCache\CachePool::delete() should return bool but return statement is missing.
  136    Method WpOop\TransientCache\CachePool::clear() should return bool but return statement is missing.
  175    Method WpOop\TransientCache\CachePool::setMultiple() should return bool but return statement is missing.
  189    Method WpOop\TransientCache\CachePool::deleteMultiple() should return bool but return statement is missing.
  304    Parameter #2 $x of method wpdb::get_col() expects int, string given.
 ------ -------------------------------------------------------------------------------------------------------------

Could you return a bool?

Discovered by @phpstan

Better exception messages

The exception that could be thrown when clearing the cache provides no meaningful explanation as to why the clearing could have failed.

There are a few exceptions that this catch could catch, but most of them will most likely never happen during cache clearing (such as this one since the cache clearing process starts by retrieving keys from the database that do start with the prefix).

Clearing errors will typically arise from an exception thrown in delete(), which itself also catches and re-throws from deleteTransient().

Ideally, the actual error message is not lost when an exception is caught and re-thrown. This puts burden on consumers to iterate through the stack trace in hopes of finding the actual reason for a failure. That process alone is sketchy at best, as the consumer would need to somehow know how long they should recurse into the stack trace in order to obtain a meaningful error message.


Suggestions:

a. Do not catch and re-thrown exceptions wherever possible
b. Re-thrown exceptions re-use the inner exception's message
c. Re-thrown exceptions append the inner exception's message to their own

Exception Thrown If Setting Same Value

The Problem

When using CachePool to set one or multiple values, an exception is thrown when the value for the specified key is already what is being set. In other words, setting the same value for the same key twice in succession will result in an error.

This is because under the hood update_option() (the function that WP uses to set transients) will return false in such a scenario.

Suggested Solution

Introduce an additional check in CachePool: if setting fails, get the current value and if it's the same as the new one - don't throw.

`has()` wrongly returns true for expired transients

The CachePool::has() method checks if the transient option exists using get_option(), while CachePool::get() retrieves the value using get_transient().

If a transient has expired but still exists in the options table, calling get_transient will result in the option record being deleted from the database. On the other hand, get_option will simple retrieve the value of the expired transient, without deleting it.

Therefore, if a transient has expired, the CachePool::has() method will find the transient and return true, while a subsequent CachePool::get() call will delete the transient and return the default value.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.