wpdesk/wp-persistence

There is no license information available for the latest version (3.0.2) of this package.

Maintainers

Package info

gitlab.com/wpdesk/library/wp-persistence

Issues

pkg:composer/wpdesk/wp-persistence

Statistics

Installs: 47 582

Dependents: 13

Suggesters: 0

Stars: 0

3.0.2 2022-04-09 12:21 UTC

README

The WP Desk Persistence Library is a robust, lightweight PHP utility designed for WordPress and WooCommerce environments. It abstracts and unifies access to different persistence layers under a clean, consistent interface. By extending the PSR-11 container standards, it enables seamless reading, writing, and deletion of data across arrays, databases, post meta, transients, and WooCommerce sessions.

The library also provides decorators to optimize performance through deferred writes (batch saving) and automatic serialization.

Key Features

  • PSR-11 Compliance: Extends psr/container to ensure standards compatibility and ease of dependency injection.
  • Unified Interface: Write and delete values using a single, clear API regardless of whether the backend is an option, transient, post metadata, or WooCommerce session.
  • Multiple Adapters: Out-of-the-box support for:
    • In-memory arrays and references.
    • WordPress Options, Transients, and Post Meta.
    • WooCommerce Sessions, Settings APIs, and Shipping Methods.
  • Performance-Oriented Decorators:
    • Delayed writes to queue database updates in memory before applying them in a single batch operation.
    • Serialization wrappers to safely store complex structures like arrays or objects in simple scalar database options.
  • Robust Exception Handling: Transparently maps lookup failures to PSR-compliant exceptions and supports fallback values.

Requirements

The minimum system requirements read from composer.json are:

  • PHP Version: 7.0 or higher
  • Key Libraries:
    • psr/container: ~1.0.0
  • WordPress Environment: Recommended when using WordPress adapters.
  • WooCommerce Environment: Required when using WooCommerce-specific session or settings adapters.

Installation

Install the library using Composer:

composer require wpdesk/wp-persistence

Autoloader Compatibility

To ensure that the correct version of the library is loaded in WordPress environments where multiple plugins might bundle different versions of the same dependency, it is highly recommended to use wpdesk/wp-autoloader.

// Standard Composer autoloader initialization
require_once 'vendor/autoload.php';

Usage

Below are examples demonstrating how to use the different containers and decorators in this package.

Basic CRUD Operations

You can use WordpressOptionsContainer to store basic configuration values.

use WPDesk\Persistence\Adapter\WordPress\WordpressOptionsContainer;

// Initialize the option-backed container with an optional namespace prefix
$container = new WordpressOptionsContainer('my_plugin_');

// Save a scalar value
$container->set('api_key', 'xyz123abc');

// Check if a value exists
if ($container->has('api_key')) {
    // Retrieve the value
    $apiKey = $container->get('api_key');
}

// Safely get a value with a fallback default without throwing exceptions
$timeout = $container->get_fallback('request_timeout', 30);

// Delete a key
$container->delete('api_key');

// Setting a value to null also deletes it
$container->set('api_key', null);

Transparent Serialization

Standard WordPress options cannot store complex structures natively without manual serialization. The SerializedPersistentContainer automates this process.

use WPDesk\Persistence\Adapter\WordPress\WordpressOptionsContainer;
use WPDesk\Persistence\Decorator\SerializedPersistentContainer;

$baseContainer = new WordpressOptionsContainer('plugin_settings_');
$serializedContainer = new SerializedPersistentContainer($baseContainer);

$settings = [
    'notifications' => true,
    'retry_limit' => 5,
    'allowed_types' => ['post', 'page']
];

// Stores serialized data under option 'plugin_settings_config'
$serializedContainer->set('config', $settings);

// Automatically unserializes to a PHP array on retrieval
$retrievedSettings = $serializedContainer->get('config');

Deferred Writes (Delaying DB Queries)

To avoid executing a database query on every set or delete call, wrap your container in DelayPersistentContainer. This implements the DeferredPersistentContainer interface.

use WPDesk\Persistence\Adapter\WordPress\WordpressOptionsContainer;
use WPDesk\Persistence\Decorator\DelayPersistentContainer;

$options = new WordpressOptionsContainer('user_pref_');
$deferred = new DelayPersistentContainer($options);

// Changes are kept in memory and do not query the database yet
$deferred->set('theme', 'dark');
$deferred->set('sidebar_collapsed', true);
$deferred->delete('old_temporary_flag');

if ($deferred->is_changed()) {
    // Persist all queued memory modifications to the database at once
    $deferred->save();
}

// Discard all unsaved memory adjustments
$deferred->reset();

Delayed Persistence to a Single Unified Value

To store multiple distinct settings keys as key-value pairs inside a single database field, use DelaySinglePersistentContainer. It implements AllDataAccessContainer.

use WPDesk\Persistence\Adapter\WordPress\WordpressOptionsContainer;
use WPDesk\Persistence\Decorator\DelaySinglePersistentContainer;

$options = new WordpressOptionsContainer();

// All keys manipulated here will end up in a single serialized option named 'my_plugin_unified_settings'
$singleOptionContainer = new DelaySinglePersistentContainer($options, 'my_plugin_unified_settings');

$singleOptionContainer->set('enabled', true);
$singleOptionContainer->set('debug_mode', false);

// Writes a single serialized array containing all values to the option
$singleOptionContainer->save();

// Read all key-value pairs
$allSettings = $singleOptionContainer->get_all();

Reference Array Persistence

You can bind a container to a referenced PHP array via ReferenceArrayContainer. Manipulating the container alters the reference target directly.

use WPDesk\Persistence\Adapter\ReferenceArrayContainer;

$settingsArray = [];
$container = new ReferenceArrayContainer($settingsArray);

$container->set('option_a', 'value_a');

// $settingsArray now contains ['option_a' => 'value_a']

WooCommerce Session Container

Store values directly inside the WooCommerce customer session using WooCommerceSessionContainer.

use WPDesk\Persistence\Adapter\WooCommerce\WooCommerceSessionContainer;

if (null !== WC()->session) {
    $sessionContainer = new WooCommerceSessionContainer(WC()->session);

    // Save temporary state for the user's cart or session
    $sessionContainer->set('selected_delivery_window', 'morning');

    $window = $sessionContainer->get('selected_delivery_window');
}

Value Resolution Table

This table illustrates the responses of has() and get() for various types of values stored in the containers.

Stored ValueGet ResultHas Result
'test''test'true
[][]true
''''true
9999 (or string '99')true
00 (or string '0')true
truetrue (or string '1')true
falsefalse (or empty string '')true
not setThrows ElementNotExistsExceptionfalse
nullThrows ElementNotExistsExceptionfalse

Backward Compatibility / Legacy APIs

When upgrading the library, please note the following legacy changes and structural updates:

Upgrading to 3.0.0

  • Null Handling: Historically, setting a key to null stored the literal value null. Since version 3.0.0, passing null to set() is treated as a removal operation, invoking delete(). Calling get() or has() on a key that was set to null will throw an ElementNotExistsException and return false, respectively.
  • Interface Methods: The PersistentContainer interface now requires the get_fallback method. Custom implementations of this interface must define this method or consume FallbackFromGetTrait.

Upgrading to 2.0.0

  • Namespace Standardization: The root namespace path was standardized. The segment Wordpress was renamed to WordPress. Ensure your class use-statements and configuration namespaces are updated to utilize WPDesk\Persistence\Adapter\WordPress\.
  • Class Renaming: The class MemoryContainer was deprecated and renamed to ArrayContainer. Change all references of MemoryContainer to ArrayContainer.

Running Tests

Unit and integration tests are configured using PHPUnit. The test suites are defined in phpunit-unit.xml and phpunit-integration.xml.

You can execute the test suites using the following Composer commands:

Unit Tests

# Run unit tests with coverage reporting
composer phpunit-unit

# Run unit tests quickly without code coverage
composer phpunit-unit-fast

Integration Tests

# Run integration tests with coverage reporting
composer phpunit-integration

# Run integration tests quickly without code coverage
composer phpunit-integration-fast

License

This library is licensed under the MIT License. See LICENSE.md for details.