first commit

This commit is contained in:
2026-03-05 13:07:40 +01:00
commit 64ba0721ee
25709 changed files with 4691006 additions and 0 deletions

View File

@@ -0,0 +1,36 @@
{
"name": "wpdesk\/wp-persistence",
"authors": [
{
"name": "Krzysiek",
"email": "krzysiek@wpdesk.pl"
}
],
"require": {
"php": ">=5.6",
"psr\/container": "^1.0"
},
"require-dev": {
"phpunit\/phpunit": "^5",
"wp-coding-standards\/wpcs": "^0.14.1",
"squizlabs\/php_codesniffer": "^3.0.2",
"wimg\/php-compatibility": "^8",
"wpdesk\/wp-wpdesk-composer": "^2.6"
},
"autoload": {
"psr-4": {
"FSVendor\\WPDesk\\Persistence\\": "src\/"
}
},
"autoload-dev": {
"psr-4": {
"FSVendor\\WPDesk\\Persistence\\Tests\\Integration\\": "tests\/integration\/"
}
},
"scripts": {
"phpunit-unit": "phpunit --configuration phpunit-unit.xml --coverage-text --colors=never",
"phpunit-unit-fast": "phpunit --configuration phpunit-unit.xml --no-coverage",
"phpunit-integration": "phpunit --configuration phpunit-integration.xml --coverage-text --colors=never",
"phpunit-integration-fast": "phpunit --configuration phpunit-integration.xml --no-coverage"
}
}

View File

@@ -0,0 +1,48 @@
<?php
namespace FSVendor\WPDesk\Persistence\Adapter;
use FSVendor\WPDesk\Persistence\ElementNotExistsException;
use FSVendor\WPDesk\Persistence\PersistentContainer;
/**
* Container that uses array as a persistent memory.
*
* @package WPDesk\Persistence
*/
class ArrayContainer implements \FSVendor\WPDesk\Persistence\PersistentContainer
{
/** @var array */
protected $array;
public function __construct(array $initial = [])
{
$this->array = $initial;
}
public function set($id, $value)
{
$this->array[$id] = $value;
}
public function delete($id)
{
unset($this->array[$id]);
}
public function has($id)
{
return \key_exists($id, $this->array);
}
public function get($id)
{
if (!isset($this->array[$id])) {
throw new \FSVendor\WPDesk\Persistence\ElementNotExistsException(\sprintf('Element %s not exists!', $id));
}
return $this->array[$id];
}
/**
* Return array that is used internally to save the data.
*
* @return array
*/
public function get_array()
{
return $this->array;
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace FSVendor\WPDesk\Persistence\Adapter;
/**
* Container that uses array as a persistent memory. When the value in container is changed, the value in
* given array is also changed using reference.
*
* @package WPDesk\Persistence
*/
final class ReferenceArrayContainer extends \FSVendor\WPDesk\Persistence\Adapter\ArrayContainer
{
/**
* @param array $referenced You have to pass this array. It can not be value.
*/
public function __construct(array &$referenced)
{
$this->array =& $referenced;
}
}

View File

@@ -0,0 +1,60 @@
<?php
namespace FSVendor\WPDesk\Persistence\Adapter\WooCommerce;
use FSVendor\WPDesk\Persistence\ElementNotExistsException;
use FSVendor\WPDesk\Persistence\PersistentContainer;
/**
* Can store data using WooCommerce settings options.
* Use when want the abstract access to \WC_Settings_API.
*
* @package WPDesk\Persistence\WooCommerce
*/
final class WooCommerceSettingsContainer implements \FSVendor\WPDesk\Persistence\PersistentContainer
{
/** @var \WC_Settings_API */
private $settings;
public function __construct(\WC_Settings_API $settings)
{
$this->settings = $settings;
}
public function get($id)
{
if (!$this->has($id)) {
throw new \FSVendor\WPDesk\Persistence\ElementNotExistsException(\sprintf('Element %s not exists!', $id));
}
return $this->settings->get_option($id);
}
public function has($id)
{
return isset($this->settings->settings[$id]);
}
public function set($id, $value)
{
if (\version_compare(\WC_VERSION, '3.4', '>=')) {
$this->settings->update_option($id, $value);
} else {
$this->settings->settings[$id] = $value;
$this->update_db_using_wordpress();
}
}
/**
* WC_Settings_API is so great that sometimes we have to manually update the data using WP update_option.
*
* @see \WC_Settings_API::process_admin_options
*/
private function update_db_using_wordpress()
{
\update_option($this->settings->get_option_key(), \apply_filters('woocommerce_settings_api_sanitized_fields_' . $this->settings->id, $this->settings->settings), 'yes');
}
public function delete($id)
{
$form_fields = $this->settings->get_form_fields();
if (isset($form_fields[$id])) {
$this->settings->settings[$id] = $this->settings->get_field_default($form_fields[$id]);
} else {
unset($this->settings->settings[$id]);
}
$this->update_db_using_wordpress();
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace FSVendor\WPDesk\Persistence\Adapter\WooCommerce;
use FSVendor\WPDesk\Persistence\ElementNotExistsException;
use FSVendor\WPDesk\Persistence\PersistentContainer;
/**
* Can store data using WooCommerce shipping instance settings options.
* Use when want the abstract access to \WC_Shipping_Method.
*
* @package WPDesk\Persistence\WooCommerce
*/
final class WooCommerceShippingInstanceContainer implements \FSVendor\WPDesk\Persistence\PersistentContainer
{
/** @var \WC_Shipping_Method */
private $method;
public function __construct(\WC_Shipping_Method $method)
{
$this->method = $method;
}
public function get($id)
{
if (!$this->has($id)) {
throw new \FSVendor\WPDesk\Persistence\ElementNotExistsException(\sprintf('Element %s not exists!', $id));
}
return $this->method->get_instance_option($id);
}
public function has($id)
{
return isset($this->method->instance_settings[$id]);
}
public function set($id, $value)
{
$this->method->instance_settings[$id] = $value;
/** @see \WC_Shipping_Method::process_admin_options */
\update_option($this->method->get_instance_option_key(), \apply_filters('woocommerce_shipping_' . $this->method->id . '_instance_settings_values', $this->method->instance_settings, $this->method), 'yes');
}
public function delete($id)
{
$form_fields = $this->method->get_instance_form_fields();
$empty_value = isset($form_fields[$id]) ? $this->method->get_field_default($form_fields[$id]) : null;
$this->set($id, $empty_value);
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace FSVendor\WPDesk\Persistence\Adapter\WordPress;
use FSVendor\WPDesk\Persistence\ElementNotExistsException;
use FSVendor\WPDesk\Persistence\PersistentContainer;
/**
* Can store data using WordPress options.
*
* @package WPDesk\Persistence\Wordpress
*/
final class WordpressOptionsContainer implements \FSVendor\WPDesk\Persistence\PersistentContainer
{
/** @var string */
private $namespace;
/**
* @param string $namespace Namespace so options in different containers would not conflict.
*/
public function __construct($namespace = '')
{
$this->namespace = $namespace;
}
public function set($id, $value)
{
\update_option($this->prepare_key_name($id), $value);
}
public function delete($id)
{
\delete_option($this->prepare_key_name($id));
}
public function has($key)
{
$fake_default = \uniqid();
return $fake_default !== \get_option($this->prepare_key_name($key), $fake_default);
}
/**
* Prepare name for key.
*
* @param string $key Key.
*
* @return string
*/
private function prepare_key_name($key)
{
return \sanitize_key($this->namespace . $key);
}
public function get($id)
{
$fake_default = \uniqid();
$value = \get_option($this->prepare_key_name($id), $fake_default);
if ($fake_default === $value) {
throw new \FSVendor\WPDesk\Persistence\ElementNotExistsException(\sprintf('Element %s not exists!', $id));
}
return $value;
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace FSVendor\WPDesk\Persistence\Adapter\WordPress;
use FSVendor\WPDesk\Persistence\PersistentContainer;
/**
* Can store data using WordPress Post metadata.
* Warning: stored string '' is considered unset.
*
* @package WPDesk\Persistence\Wordpress
*/
final class WordpressPostMetaContainer implements \FSVendor\WPDesk\Persistence\PersistentContainer
{
/** @var int */
private $post_id;
/**
* @param int $post_id Id of the WordPress post.
*/
public function __construct($post_id)
{
$this->post_id = (int) $post_id;
}
public function set($key, $value)
{
\update_post_meta($this->post_id, $key, $value);
}
public function get($key)
{
return \get_post_meta($this->post_id, $key, \true);
}
/**
* @param string $id
*
* @return bool
*/
public function has($key)
{
return \metadata_exists('post', $this->post_id, $key);
}
public function delete($key)
{
\delete_post_meta($this->post_id, $key);
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace FSVendor\WPDesk\Persistence\Adapter\WordPress;
use FSVendor\WPDesk\Persistence\PersistentContainer;
/**
* Can store data using WordPress options. All data are stored in one option as serialized data.
*
* @package WPDesk\Persistence\Wordpress
*/
final class WordpressSerializedOptionsContainer implements \FSVendor\WPDesk\Persistence\PersistentContainer
{
/** @var string */
private $option_name;
/** @var array */
private $option_value;
/**
* @param string option_name
*/
public function __construct($option_name)
{
$this->option_name = $option_name;
}
/**
* @return void
*/
private function refresh_value()
{
$this->option_value = \get_option($this->option_name, []);
}
public function set($id, $value)
{
$this->refresh_value();
$this->option_value[$id] = $value;
\update_option($this->option_name, $this->option_value);
}
public function delete($id)
{
$this->refresh_value();
unset($this->option_value[$id]);
\update_option($this->option_name, $this->option_value);
}
public function has($key)
{
$this->refresh_value();
return isset($this->option_value[$key]);
}
public function get($id)
{
$this->refresh_value();
if (!isset($this->option_value[$id])) {
throw new \FSVendor\WPDesk\Persistence\Adapter\WordPress\ElementNotFoundException(\sprintf('Element %s not exists!', $id));
}
return $this->option_value[$id];
}
}

View File

@@ -0,0 +1,66 @@
<?php
namespace FSVendor\WPDesk\Persistence\Adapter\WordPress;
use FSVendor\WPDesk\Persistence\ElementNotExistsException;
use FSVendor\WPDesk\Persistence\PersistentContainer;
/**
* Can store data using WordPress transients.
* Warning: stored false is considered unset.
*
* @package WPDesk\Persistence\Wordpress
*/
final class WordpressTransientContainer implements \FSVendor\WPDesk\Persistence\PersistentContainer
{
/** @var int */
private $expiration;
/** @var string */
private $namespace;
/**
* @param string $namespace Namespace so transients in different containers would not conflict.
* @param float|int $expiration Expire transient after xx seconds.
*/
public function __construct($namespace = '', $expiration = DAY_IN_SECONDS)
{
$this->expiration = (int) $expiration;
$this->namespace = $namespace;
}
public function set($id, $value)
{
\set_transient($this->prepare_key_name($id), $value, $this->expiration);
}
/**
* Warning: stored false is considered unset.
*
* @param string $id
*
* @return bool
*/
public function has($id)
{
return \get_transient($this->prepare_key_name($id)) !== \false;
}
public function delete($id)
{
\delete_transient($this->prepare_key_name($id));
}
/**
* Prepare transient name for key.
*
* @param string $key Key.
*
* @return string
*/
private function prepare_key_name($key)
{
return \sanitize_key($this->namespace . $key);
}
public function get($id)
{
$value = \get_transient($this->prepare_key_name($id));
if (\false === $value) {
throw new \FSVendor\WPDesk\Persistence\ElementNotExistsException(\sprintf('Element %s not exists!', $id));
}
return $value;
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace FSVendor\WPDesk\Persistence;
use Psr\Container\ContainerInterface;
/**
* Container that allows to get all data stored by container.
*
* @package WPDesk\Persistence
*/
interface AllDataAccessContainer extends \Psr\Container\ContainerInterface
{
/**
* Get all values.
*
* @return array
*/
public function get_all();
}

View File

@@ -0,0 +1,79 @@
<?php
namespace FSVendor\WPDesk\Persistence\Decorator;
use FSVendor\WPDesk\Persistence\DeferredPersistentContainer;
use FSVendor\WPDesk\Persistence\ElementNotExistsException;
use FSVendor\WPDesk\Persistence\PersistentContainer;
/**
* You can use this class to delay write access to any PersistenceContainer.
*
* @package WPDesk\Persistence
*/
class DelayPersistentContainer implements \FSVendor\WPDesk\Persistence\DeferredPersistentContainer
{
/**
* Container with deferred access.
*
* @var PersistentContainer
*/
protected $container;
/**
* Data that has been set but not yet saved to $container.
*
* @var array
*/
protected $internal_data = [];
/**
* The keys that was changed in using internal data.
*
* @var bool[]
*/
protected $changed = [];
public function __construct(\FSVendor\WPDesk\Persistence\PersistentContainer $container)
{
$this->container = $container;
}
public function get($id)
{
if (isset($this->changed[$id]) && $this->changed[$id]) {
if (isset($this->internal_data[$id])) {
return $this->internal_data[$id];
}
throw new \FSVendor\WPDesk\Persistence\ElementNotExistsException(\sprintf('Element %s not exists!', $id));
}
return $this->container->get($id);
}
public function has($id)
{
if (isset($this->changed[$id]) && $this->changed[$id]) {
return isset($this->internal_data[$id]);
}
return $this->container->has($id);
}
public function save()
{
foreach ($this->changed as $key => $value) {
$this->container->set($key, $this->internal_data[$key]);
}
$this->reset();
}
public function is_changed()
{
return !empty($this->changed);
}
public function reset()
{
$this->changed = [];
}
public function set($id, $value)
{
$this->changed[$id] = \true;
$this->internal_data[$id] = $value;
}
public function delete($id)
{
$this->changed[$id] = \true;
unset($this->internal_data[$id]);
}
}

View File

@@ -0,0 +1,75 @@
<?php
namespace FSVendor\WPDesk\Persistence\Decorator;
use FSVendor\WPDesk\Persistence\ElementNotExistsException;
use FSVendor\WPDesk\Persistence\PersistentContainer;
use FSVendor\WPDesk\Persistence\AllDataAccessContainer;
/**
* You can use this class to delay write access to any PersistenceContainer and save it as single value.
*
* @package WPDesk\Persistence
*/
final class DelaySinglePersistentContainer extends \FSVendor\WPDesk\Persistence\Decorator\DelayPersistentContainer implements \FSVendor\WPDesk\Persistence\AllDataAccessContainer
{
/**
* Key where the data will be saved.
*
* @var string
*/
private $key;
public function __construct(\FSVendor\WPDesk\Persistence\PersistentContainer $container, $key)
{
parent::__construct($container);
$this->key = $key;
}
public function get($id)
{
if (isset($this->changed[$id]) && $this->changed[$id]) {
if (isset($this->internal_data[$id])) {
return $this->internal_data[$id];
}
} else {
$data = \unserialize($this->container->get($this->key));
if (\is_array($data) && isset($data[$id])) {
return $data[$id];
}
}
throw new \FSVendor\WPDesk\Persistence\ElementNotExistsException(\sprintf('Element %s not exists!', $id));
}
public function has($id)
{
if (isset($this->changed[$id]) && $this->changed[$id]) {
return isset($this->internal_data[$id]);
}
if ($this->container->has($this->key)) {
$data = \unserialize($this->container->get($this->key));
return \is_array($data) && isset($data[$id]);
}
return \false;
}
public function save()
{
if ($this->is_changed()) {
$this->container->set($this->key, \serialize($this->internal_data));
$this->reset();
}
}
/**
* @see AllDataAccessContainer::get_all()
*/
public function get_all()
{
if (!empty($this->changed)) {
if (!empty($this->internal_data)) {
return $this->internal_data;
}
} else {
$data = \unserialize($this->container->get($this->key));
if (!empty($data)) {
return $data;
}
}
return array();
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace FSVendor\WPDesk\Persistence;
use Psr\Container\ContainerInterface;
/**
* Container that persists values only after save method is used.
*
* @package WPDesk\Persistence
*/
interface DeferredPersistentContainer extends \FSVendor\WPDesk\Persistence\PersistentContainer
{
/**
* Save changed data.
*
* @return void
*/
public function save();
/**
* Is there any new data to save.
*
* @return bool
*/
public function is_changed();
/**
* Reset data to last saved values. If remote repository is used the data can be retrived from it.
*
* @return void
*/
public function reset();
}

View File

@@ -0,0 +1,11 @@
<?php
namespace FSVendor\WPDesk\Persistence;
use Psr\Container\NotFoundExceptionInterface;
/**
* @package WPDesk\Persistence
*/
class ElementNotExistsException extends \RuntimeException implements \Psr\Container\NotFoundExceptionInterface
{
}

View File

@@ -0,0 +1,31 @@
<?php
namespace FSVendor\WPDesk\Persistence;
use Psr\Container\ContainerInterface;
/**
* Container that you can use to save some values.
* When class require only read capabilities use ContainerInterface. When requires to write use this interface.
*
* @package WPDesk\Persistence
*/
interface PersistentContainer extends \Psr\Container\ContainerInterface
{
/**
* Set value for a given key.
*
* @param string $id Identifier of the entry to look for.
* @param array|int|string|float $value Value should not be an object or callable.
*
* @return void
*/
public function set($id, $value);
/**
* Clear value from a given key.
*
* @param string $id Identifier of the entry to look for.
*
* @return void
*/
public function delete($id);
}