Initial Commit
This commit is contained in:
44
dependencies/berlindb/core/autoloader.php
vendored
Normal file
44
dependencies/berlindb/core/autoloader.php
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace WP_Ultimo\Dependencies;
|
||||
|
||||
/**
|
||||
* Autoloader.
|
||||
*
|
||||
* @package Database
|
||||
* @copyright Copyright (c) 2021
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
* @since 2.0.0
|
||||
*/
|
||||
// Exit if accessed directly.
|
||||
\defined('ABSPATH') || exit;
|
||||
// Register a closure to autoload BerlinDB.
|
||||
\spl_autoload_register(
|
||||
/**
|
||||
* Closure of the autoloader.
|
||||
*
|
||||
* @param string $class_name The fully-qualified class name.
|
||||
* @return void
|
||||
*/
|
||||
static function ($class_name = '') {
|
||||
// Project namespace & length.
|
||||
$project_namespace = 'BerlinDB\\Database\\';
|
||||
$length = \strlen($project_namespace);
|
||||
// Bail if class is not in this namespace.
|
||||
if (0 !== \strncmp($project_namespace, $class_name, $length)) {
|
||||
return;
|
||||
}
|
||||
// Setup file parts.
|
||||
$format = '%1$s/src/%2$s.php';
|
||||
$path = __DIR__;
|
||||
$name = \str_replace('\\', '/', \substr($class_name, $length));
|
||||
// Parse class and namespace to file.
|
||||
$file = \sprintf($format, $path, $name);
|
||||
// Bail if file does not exist.
|
||||
if (!\is_file($file)) {
|
||||
return;
|
||||
}
|
||||
// Require the file.
|
||||
require_once $file;
|
||||
}
|
||||
);
|
298
dependencies/berlindb/core/src/Database/Base.php
vendored
Normal file
298
dependencies/berlindb/core/src/Database/Base.php
vendored
Normal file
@ -0,0 +1,298 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Base Custom Database Class.
|
||||
*
|
||||
* @package Database
|
||||
* @subpackage Base
|
||||
* @copyright Copyright (c) 2021
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
* @since 1.0.0
|
||||
*/
|
||||
namespace WP_Ultimo\Dependencies\BerlinDB\Database;
|
||||
|
||||
// Exit if accessed directly
|
||||
\defined('ABSPATH') || exit;
|
||||
/**
|
||||
* The base class that all other database base classes extend.
|
||||
*
|
||||
* This class attempts to provide some universal immutability to all other
|
||||
* classes that extend it, starting with a magic getter, but likely expanding
|
||||
* into a magic call handler and others.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Base
|
||||
{
|
||||
/**
|
||||
* The name of the PHP global that contains the primary database interface.
|
||||
*
|
||||
* For example, WordPress traditionally uses 'wpdb', but other applications
|
||||
* may use something else, or you may be doing something really cool that
|
||||
* requires a custom interface.
|
||||
*
|
||||
* A future version of this utility may abstract this out entirely, so
|
||||
* custom calls to the get_db() should be avoided if at all possible.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $db_global = 'wpdb';
|
||||
/** Global Properties *****************************************************/
|
||||
/**
|
||||
* Global prefix used for tables/hooks/cache-groups/etc...
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix = '';
|
||||
/**
|
||||
* The last database error, if any.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var mixed
|
||||
*/
|
||||
protected $last_error = \false;
|
||||
/** Public ****************************************************************/
|
||||
/**
|
||||
* Magic isset'ter for immutability.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function __isset($key = '')
|
||||
{
|
||||
// No more uppercase ID properties ever
|
||||
if ('ID' === $key) {
|
||||
$key = 'id';
|
||||
}
|
||||
// Class method to try and call
|
||||
$method = "get_{$key}";
|
||||
// Return property if exists
|
||||
if (\method_exists($this, $method)) {
|
||||
return \true;
|
||||
// Return get method results if exists
|
||||
} elseif (\property_exists($this, $key)) {
|
||||
return \true;
|
||||
}
|
||||
// Return false if not exists
|
||||
return \false;
|
||||
}
|
||||
/**
|
||||
* Magic getter for immutability.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($key = '')
|
||||
{
|
||||
// No more uppercase ID properties ever
|
||||
if ('ID' === $key) {
|
||||
$key = 'id';
|
||||
}
|
||||
// Class method to try and call
|
||||
$method = "get_{$key}";
|
||||
// Return property if exists
|
||||
if (\method_exists($this, $method)) {
|
||||
return \call_user_func(array($this, $method));
|
||||
// Return get method results if exists
|
||||
} elseif (\property_exists($this, $key)) {
|
||||
return $this->{$key};
|
||||
}
|
||||
// Return null if not exists
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Converts the given object to an array.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return array Array version of the given object.
|
||||
*/
|
||||
public function to_array()
|
||||
{
|
||||
return \get_object_vars($this);
|
||||
}
|
||||
/** Protected *************************************************************/
|
||||
/**
|
||||
* Maybe append the prefix to string.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $sep
|
||||
* @return string
|
||||
*/
|
||||
protected function apply_prefix($string = '', $sep = '_')
|
||||
{
|
||||
return !empty($this->prefix) ? "{$this->prefix}{$sep}{$string}" : $string;
|
||||
}
|
||||
/**
|
||||
* Return the first letters of a string of words with a separator.
|
||||
*
|
||||
* Used primarily to guess at table aliases when none is manually set.
|
||||
*
|
||||
* Applies the following formatting to a string:
|
||||
* - Trim whitespace
|
||||
* - No accents
|
||||
* - No trailing underscores
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $sep
|
||||
* @return string
|
||||
*/
|
||||
protected function first_letters($string = '', $sep = '_')
|
||||
{
|
||||
// Set empty default return value
|
||||
$retval = '';
|
||||
// Bail if empty or not a string
|
||||
if (empty($string) || !\is_string($string)) {
|
||||
return $retval;
|
||||
}
|
||||
// Trim spaces off the ends
|
||||
$unspace = \trim($string);
|
||||
// Only non-accented table names (avoid truncation)
|
||||
$accents = remove_accents($unspace);
|
||||
// Only lowercase letters are allowed
|
||||
$lower = \strtolower($accents);
|
||||
// Explode into parts
|
||||
$parts = \explode($sep, $lower);
|
||||
// Loop through parts and concatenate the first letters together
|
||||
foreach ($parts as $part) {
|
||||
$retval .= \substr($part, 0, 1);
|
||||
}
|
||||
// Return the result
|
||||
return $retval;
|
||||
}
|
||||
/**
|
||||
* Sanitize a table name string.
|
||||
*
|
||||
* Used to make sure that a table name value meets MySQL expectations.
|
||||
*
|
||||
* Applies the following formatting to a string:
|
||||
* - Trim whitespace
|
||||
* - No accents
|
||||
* - No special characters
|
||||
* - No hyphens
|
||||
* - No double underscores
|
||||
* - No trailing underscores
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $name The name of the database table
|
||||
*
|
||||
* @return string Sanitized database table name
|
||||
*/
|
||||
protected function sanitize_table_name($name = '')
|
||||
{
|
||||
// Bail if empty or not a string
|
||||
if (empty($name) || !\is_string($name)) {
|
||||
return \false;
|
||||
}
|
||||
// Trim spaces off the ends
|
||||
$unspace = \trim($name);
|
||||
// Only non-accented table names (avoid truncation)
|
||||
$accents = remove_accents($unspace);
|
||||
// Only lowercase characters, hyphens, and dashes (avoid index corruption)
|
||||
$lower = sanitize_key($accents);
|
||||
// Replace hyphens with single underscores
|
||||
$under = \str_replace('-', '_', $lower);
|
||||
// Single underscores only
|
||||
$single = \str_replace('__', '_', $under);
|
||||
// Remove trailing underscores
|
||||
$clean = \trim($single, '_');
|
||||
// Bail if table name was garbaged
|
||||
if (empty($clean)) {
|
||||
return \false;
|
||||
}
|
||||
// Return the cleaned table name
|
||||
return $clean;
|
||||
}
|
||||
/**
|
||||
* Set class variables from arguments.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param array $args
|
||||
*/
|
||||
protected function set_vars($args = array())
|
||||
{
|
||||
// Bail if empty or not an array
|
||||
if (empty($args)) {
|
||||
return;
|
||||
}
|
||||
// Cast to an array
|
||||
if (!\is_array($args)) {
|
||||
$args = (array) $args;
|
||||
}
|
||||
// Set all properties
|
||||
foreach ($args as $key => $value) {
|
||||
$this->{$key} = $value;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return the global database interface.
|
||||
*
|
||||
* See: https://core.trac.wordpress.org/ticket/31556
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return \wpdb Database interface, or False if not set
|
||||
*/
|
||||
protected function get_db()
|
||||
{
|
||||
// Default database return value (might change)
|
||||
$retval = \false;
|
||||
// Look for a commonly used global database interface
|
||||
if (isset($GLOBALS[$this->db_global])) {
|
||||
$retval = $GLOBALS[$this->db_global];
|
||||
}
|
||||
/*
|
||||
* Developer note:
|
||||
*
|
||||
* It should be impossible for a database table to be interacted with
|
||||
* before the primary database interface is setup.
|
||||
*
|
||||
* However, because applications are complicated, it is unsafe to assume
|
||||
* anything, so this silently returns false instead of halting everything.
|
||||
*
|
||||
* If you are here because this method is returning false for you, that
|
||||
* means the database table is being invoked too early in the lifecycle
|
||||
* of the application.
|
||||
*
|
||||
* In WordPress, that means before the $wpdb global is created; in other
|
||||
* environments, you will need to adjust accordingly.
|
||||
*/
|
||||
// Return the database interface
|
||||
return $retval;
|
||||
}
|
||||
/**
|
||||
* Check if an operation succeeded.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param mixed $result
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_success($result = \false)
|
||||
{
|
||||
// Bail if no row exists
|
||||
if (empty($result)) {
|
||||
$retval = \false;
|
||||
// Bail if an error occurred
|
||||
} elseif (is_wp_error($result)) {
|
||||
$this->last_error = $result;
|
||||
$retval = \false;
|
||||
// No errors
|
||||
} else {
|
||||
$retval = \true;
|
||||
}
|
||||
// Return the result
|
||||
return (bool) $retval;
|
||||
}
|
||||
}
|
803
dependencies/berlindb/core/src/Database/Column.php
vendored
Normal file
803
dependencies/berlindb/core/src/Database/Column.php
vendored
Normal file
@ -0,0 +1,803 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Base Custom Database Table Column Class.
|
||||
*
|
||||
* @package Database
|
||||
* @subpackage Column
|
||||
* @copyright Copyright (c) 2021
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
* @since 1.0.0
|
||||
*/
|
||||
namespace WP_Ultimo\Dependencies\BerlinDB\Database;
|
||||
|
||||
// Exit if accessed directly
|
||||
\defined('ABSPATH') || exit;
|
||||
/**
|
||||
* Base class used for each column for a custom table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @see Column::__construct() for accepted arguments.
|
||||
*/
|
||||
class Column extends Base
|
||||
{
|
||||
/** Table Attributes ******************************************************/
|
||||
/**
|
||||
* Name for the database column.
|
||||
*
|
||||
* Required. Must contain lowercase alphabetical characters only. Use of any
|
||||
* other character (number, ascii, unicode, emoji, etc...) will result in
|
||||
* fatal application errors.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
public $name = '';
|
||||
/**
|
||||
* Type of database column.
|
||||
*
|
||||
* See: https://dev.mysql.com/doc/en/data-types.html
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
public $type = '';
|
||||
/**
|
||||
* Length of database column.
|
||||
*
|
||||
* See: https://dev.mysql.com/doc/en/storage-requirements.html
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
public $length = \false;
|
||||
/**
|
||||
* Is integer unsigned?
|
||||
*
|
||||
* See: https://dev.mysql.com/doc/en/numeric-type-overview.html
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $unsigned = \true;
|
||||
/**
|
||||
* Is integer filled with zeroes?
|
||||
*
|
||||
* See: https://dev.mysql.com/doc/en/numeric-type-overview.html
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $zerofill = \false;
|
||||
/**
|
||||
* Is data in a binary format?
|
||||
*
|
||||
* See: https://dev.mysql.com/doc/en/binary-varbinary.html
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $binary = \false;
|
||||
/**
|
||||
* Is null an allowed value?
|
||||
*
|
||||
* See: https://dev.mysql.com/doc/en/data-type-defaults.html
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $allow_null = \false;
|
||||
/**
|
||||
* Typically empty/null, or date value.
|
||||
*
|
||||
* See: https://dev.mysql.com/doc/en/data-type-defaults.html
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
public $default = '';
|
||||
/**
|
||||
* auto_increment, etc...
|
||||
*
|
||||
* See: https://dev.mysql.com/doc/en/data-type-defaults.html
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
public $extra = '';
|
||||
/**
|
||||
* Typically inherited from the database interface (wpdb).
|
||||
*
|
||||
* By default, this will use the globally available database encoding. You
|
||||
* most likely do not want to change this; if you do, you already know what
|
||||
* to do.
|
||||
*
|
||||
* See: https://dev.mysql.com/doc/mysql/en/charset-column.html
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
public $encoding = '';
|
||||
/**
|
||||
* Typically inherited from the database interface (wpdb).
|
||||
*
|
||||
* By default, this will use the globally available database collation. You
|
||||
* most likely do not want to change this; if you do, you already know what
|
||||
* to do.
|
||||
*
|
||||
* See: https://dev.mysql.com/doc/mysql/en/charset-column.html
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
public $collation = '';
|
||||
/**
|
||||
* Typically empty; probably ignore.
|
||||
*
|
||||
* By default, columns do not have comments. This is unused by any other
|
||||
* relative code, but you can include less than 1024 characters here.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
public $comment = '';
|
||||
/** Special Attributes ****************************************************/
|
||||
/**
|
||||
* Is this the primary column?
|
||||
*
|
||||
* By default, columns are not the primary column. This is used by the Query
|
||||
* class for several critical functions, including (but not limited to) the
|
||||
* cache key, meta-key relationships, auto-incrementing, etc...
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $primary = \false;
|
||||
/**
|
||||
* Is this the column used as a created date?
|
||||
*
|
||||
* By default, columns do not represent the date a value was first entered.
|
||||
* This is used by the Query class to set its value automatically to the
|
||||
* current datetime value immediately before insert.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $created = \false;
|
||||
/**
|
||||
* Is this the column used as a modified date?
|
||||
*
|
||||
* By default, columns do not represent the date a value was last changed.
|
||||
* This is used by the Query class to update its value automatically to the
|
||||
* current datetime value immediately before insert|update.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $modified = \false;
|
||||
/**
|
||||
* Is this the column used as a unique universal identifier?
|
||||
*
|
||||
* By default, columns are not UUIDs. This is used by the Query class to
|
||||
* generate a unique string that can be used to identify a row in a database
|
||||
* table, typically in such a way that is unrelated to the row data itself.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $uuid = \false;
|
||||
/** Query Attributes ******************************************************/
|
||||
/**
|
||||
* What is the string-replace pattern?
|
||||
*
|
||||
* By default, column patterns will be guessed based on their type. Set this
|
||||
* manually to `%s|%d|%f` only if you are doing something weird, or are
|
||||
* explicitly storing numeric values in text-based column types.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
public $pattern = '';
|
||||
/**
|
||||
* Is this column searchable?
|
||||
*
|
||||
* By default, columns are not searchable. When `true`, the Query class will
|
||||
* add this column to the results of search queries.
|
||||
*
|
||||
* Avoid setting to `true` on large blobs of text, unless you've optimized
|
||||
* your database server to accommodate these kinds of queries.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $searchable = \false;
|
||||
/**
|
||||
* Is this column a date?
|
||||
*
|
||||
* By default, columns do not support date queries. When `true`, the Query
|
||||
* class will accept complex statements to help narrow results down to
|
||||
* specific periods of time for values in this column.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $date_query = \false;
|
||||
/**
|
||||
* Is this column used in orderby?
|
||||
*
|
||||
* By default, columns are not sortable. This ensures that the database
|
||||
* table does not perform costly operations on unindexed columns or columns
|
||||
* of an inefficient type.
|
||||
*
|
||||
* You can safely turn this on for most numeric columns, indexed columns,
|
||||
* and text columns with intentionally limited lengths.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $sortable = \false;
|
||||
/**
|
||||
* Is __in supported?
|
||||
*
|
||||
* By default, columns support being queried using an `IN` statement. This
|
||||
* allows the Query class to retrieve rows that match your array of values.
|
||||
*
|
||||
* Consider setting this to `false` for longer text columns.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $in = \true;
|
||||
/**
|
||||
* Is __not_in supported?
|
||||
*
|
||||
* By default, columns support being queried using a `NOT IN` statement.
|
||||
* This allows the Query class to retrieve rows that do not match your array
|
||||
* of values.
|
||||
*
|
||||
* Consider setting this to `false` for longer text columns.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $not_in = \true;
|
||||
/** Cache Attributes ******************************************************/
|
||||
/**
|
||||
* Does this column have its own cache key?
|
||||
*
|
||||
* By default, only primary columns are used as cache keys. If this column
|
||||
* is unique, or is frequently used to get database results, you may want to
|
||||
* consider setting this to true.
|
||||
*
|
||||
* Use in conjunction with a database index for speedy queries.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
public $cache_key = \false;
|
||||
/** Action Attributes *****************************************************/
|
||||
/**
|
||||
* Does this column fire a transition action when it's value changes?
|
||||
*
|
||||
* By default, columns do not fire transition actions. In some cases, it may
|
||||
* be desirable to know when a database value changes, and what the old and
|
||||
* new values are when that happens.
|
||||
*
|
||||
* The Query class is responsible for triggering the event action.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
public $transition = \false;
|
||||
/** Callback Attributes ***************************************************/
|
||||
/**
|
||||
* Maybe validate this data before it is written to the database.
|
||||
*
|
||||
* By default, column data is validated based on the type of column that it
|
||||
* is. You can set this to a callback function of your choice to override
|
||||
* the default validation behavior.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
public $validate = '';
|
||||
/**
|
||||
* Array of capabilities used to interface with this column.
|
||||
*
|
||||
* These are used by the Query class to allow and disallow CRUD access to
|
||||
* column data, typically based on roles or capabilities.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var array
|
||||
*/
|
||||
public $caps = array();
|
||||
/**
|
||||
* Array of possible aliases this column can be referred to as.
|
||||
*
|
||||
* These are used by the Query class to allow for columns to be renamed
|
||||
* without requiring complex architectural backwards compatibility support.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var array
|
||||
*/
|
||||
public $aliases = array();
|
||||
/**
|
||||
* Array of possible relationships this column has with columns in other
|
||||
* database tables.
|
||||
*
|
||||
* These are typically unenforced foreign keys, and are used by the Query
|
||||
* class to help prime related items.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var array
|
||||
*/
|
||||
public $relationships = array();
|
||||
/** Methods ***************************************************************/
|
||||
/**
|
||||
* Sets up the order query, based on the query vars passed.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string|array $args {
|
||||
* Optional. Array or query string of order query parameters. Default empty.
|
||||
*
|
||||
* @type string $name Name of database column
|
||||
* @type string $type Type of database column
|
||||
* @type int $length Length of database column
|
||||
* @type bool $unsigned Is integer unsigned?
|
||||
* @type bool $zerofill Is integer filled with zeroes?
|
||||
* @type bool $binary Is data in a binary format?
|
||||
* @type bool $allow_null Is null an allowed value?
|
||||
* @type mixed $default Typically empty/null, or date value
|
||||
* @type string $extra auto_increment, etc...
|
||||
* @type string $encoding Typically inherited from wpdb
|
||||
* @type string $collation Typically inherited from wpdb
|
||||
* @type string $comment Typically empty
|
||||
* @type bool $pattern What is the string-replace pattern?
|
||||
* @type bool $primary Is this the primary column?
|
||||
* @type bool $created Is this the column used as a created date?
|
||||
* @type bool $modified Is this the column used as a modified date?
|
||||
* @type bool $uuid Is this the column used as a universally unique identifier?
|
||||
* @type bool $searchable Is this column searchable?
|
||||
* @type bool $sortable Is this column used in orderby?
|
||||
* @type bool $date_query Is this column a datetime?
|
||||
* @type bool $in Is __in supported?
|
||||
* @type bool $not_in Is __not_in supported?
|
||||
* @type bool $cache_key Is this column queried independently?
|
||||
* @type bool $transition Does this column transition between changes?
|
||||
* @type string $validate A callback function used to validate on save.
|
||||
* @type array $caps Array of capabilities to check.
|
||||
* @type array $aliases Array of possible column name aliases.
|
||||
* @type array $relationships Array of columns in other tables this column relates to.
|
||||
* }
|
||||
*/
|
||||
public function __construct($args = array())
|
||||
{
|
||||
// Parse arguments
|
||||
$r = $this->parse_args($args);
|
||||
// Maybe set variables from arguments
|
||||
if (!empty($r)) {
|
||||
$this->set_vars($r);
|
||||
}
|
||||
}
|
||||
/** Argument Handlers *****************************************************/
|
||||
/**
|
||||
* Parse column arguments
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param array $args Default empty array.
|
||||
* @return array
|
||||
*/
|
||||
private function parse_args($args = array())
|
||||
{
|
||||
// Parse arguments
|
||||
$r = wp_parse_args($args, array(
|
||||
// Table
|
||||
'name' => '',
|
||||
'type' => '',
|
||||
'length' => '',
|
||||
'unsigned' => \false,
|
||||
'zerofill' => \false,
|
||||
'binary' => \false,
|
||||
'allow_null' => \false,
|
||||
'default' => '',
|
||||
'extra' => '',
|
||||
'encoding' => $this->get_db()->charset,
|
||||
'collation' => $this->get_db()->collate,
|
||||
'comment' => '',
|
||||
// Query
|
||||
'pattern' => \false,
|
||||
'searchable' => \false,
|
||||
'sortable' => \false,
|
||||
'date_query' => \false,
|
||||
'transition' => \false,
|
||||
'in' => \true,
|
||||
'not_in' => \true,
|
||||
// Special
|
||||
'primary' => \false,
|
||||
'created' => \false,
|
||||
'modified' => \false,
|
||||
'uuid' => \false,
|
||||
// Cache
|
||||
'cache_key' => \false,
|
||||
// Validation
|
||||
'validate' => '',
|
||||
// Capabilities
|
||||
'caps' => array(),
|
||||
// Backwards Compatibility
|
||||
'aliases' => array(),
|
||||
// Column Relationships
|
||||
'relationships' => array(),
|
||||
));
|
||||
// Force some arguments for special column types
|
||||
$r = $this->special_args($r);
|
||||
// Set the args before they are sanitized
|
||||
$this->set_vars($r);
|
||||
// Return array
|
||||
return $this->validate_args($r);
|
||||
}
|
||||
/**
|
||||
* Validate arguments after they are parsed.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param array $args Default empty array.
|
||||
* @return array
|
||||
*/
|
||||
private function validate_args($args = array())
|
||||
{
|
||||
// Sanitization callbacks
|
||||
$callbacks = array('name' => 'sanitize_key', 'type' => 'strtoupper', 'length' => 'intval', 'unsigned' => 'wp_validate_boolean', 'zerofill' => 'wp_validate_boolean', 'binary' => 'wp_validate_boolean', 'allow_null' => 'wp_validate_boolean', 'default' => array($this, 'sanitize_default'), 'extra' => 'wu_kses_data', 'encoding' => 'wu_kses_data', 'collation' => 'wu_kses_data', 'comment' => 'wu_kses_data', 'primary' => 'wp_validate_boolean', 'created' => 'wp_validate_boolean', 'modified' => 'wp_validate_boolean', 'uuid' => 'wp_validate_boolean', 'searchable' => 'wp_validate_boolean', 'sortable' => 'wp_validate_boolean', 'date_query' => 'wp_validate_boolean', 'transition' => 'wp_validate_boolean', 'in' => 'wp_validate_boolean', 'not_in' => 'wp_validate_boolean', 'cache_key' => 'wp_validate_boolean', 'pattern' => array($this, 'sanitize_pattern'), 'validate' => array($this, 'sanitize_validation'), 'caps' => array($this, 'sanitize_capabilities'), 'aliases' => array($this, 'sanitize_aliases'), 'relationships' => array($this, 'sanitize_relationships'));
|
||||
// Default args array
|
||||
$r = array();
|
||||
// Loop through and try to execute callbacks
|
||||
foreach ($args as $key => $value) {
|
||||
// Callback is callable
|
||||
if (isset($callbacks[$key]) && \is_callable($callbacks[$key])) {
|
||||
$r[$key] = \call_user_func($callbacks[$key], $value ?? "");
|
||||
// Callback is malformed so just let it through to avoid breakage
|
||||
} else {
|
||||
$r[$key] = $value;
|
||||
}
|
||||
}
|
||||
// Return sanitized arguments
|
||||
return $r;
|
||||
}
|
||||
/**
|
||||
* Force column arguments for special column types
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param array $args Default empty array.
|
||||
* @return array
|
||||
*/
|
||||
private function special_args($args = array())
|
||||
{
|
||||
// Primary key columns are always used as cache keys
|
||||
if (!empty($args['primary'])) {
|
||||
$args['cache_key'] = \true;
|
||||
// All UUID columns need to follow a very specific pattern
|
||||
} elseif (!empty($args['uuid'])) {
|
||||
$args['name'] = 'uuid';
|
||||
$args['type'] = 'varchar';
|
||||
$args['length'] = '100';
|
||||
$args['in'] = \false;
|
||||
$args['not_in'] = \false;
|
||||
$args['searchable'] = \false;
|
||||
$args['sortable'] = \false;
|
||||
}
|
||||
// Return args
|
||||
return (array) $args;
|
||||
}
|
||||
/** Public Helpers ********************************************************/
|
||||
/**
|
||||
* Return if a column type is numeric or not.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @return bool
|
||||
*/
|
||||
public function is_numeric()
|
||||
{
|
||||
return $this->is_type(array('tinyint', 'int', 'mediumint', 'bigint'));
|
||||
}
|
||||
/** Private Helpers *******************************************************/
|
||||
/**
|
||||
* Return if this column is of a certain type.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param mixed $type Default empty string. The type to check. Also accepts an array.
|
||||
* @return bool True if of type, False if not
|
||||
*/
|
||||
private function is_type($type = '')
|
||||
{
|
||||
// If string, cast to array
|
||||
if (\is_string($type)) {
|
||||
$type = (array) $type;
|
||||
}
|
||||
// Make them lowercase
|
||||
$types = \array_map('strtolower', $type);
|
||||
// Return if match or not
|
||||
return (bool) \in_array(\strtolower($this->type), $types, \true);
|
||||
}
|
||||
/** Private Sanitizers ****************************************************/
|
||||
/**
|
||||
* Sanitize capabilities array
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param array $caps Default empty array.
|
||||
* @return array
|
||||
*/
|
||||
private function sanitize_capabilities($caps = array())
|
||||
{
|
||||
return wp_parse_args($caps, array('select' => 'exist', 'insert' => 'exist', 'update' => 'exist', 'delete' => 'exist'));
|
||||
}
|
||||
/**
|
||||
* Sanitize aliases array using `sanitize_key()`
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param array $aliases Default empty array.
|
||||
* @return array
|
||||
*/
|
||||
private function sanitize_aliases($aliases = array())
|
||||
{
|
||||
return \array_map('sanitize_key', $aliases);
|
||||
}
|
||||
/**
|
||||
* Sanitize relationships array
|
||||
*
|
||||
* @todo
|
||||
* @since 1.0.0
|
||||
* @param array $relationships Default empty array.
|
||||
* @return array
|
||||
*/
|
||||
private function sanitize_relationships($relationships = array())
|
||||
{
|
||||
return \array_filter($relationships);
|
||||
}
|
||||
/**
|
||||
* Sanitize the default value
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param string $default
|
||||
* @return string|null
|
||||
*/
|
||||
private function sanitize_default($default = '')
|
||||
{
|
||||
// Null
|
||||
if (\true === $this->allow_null && \is_null($default)) {
|
||||
return null;
|
||||
// String
|
||||
} elseif (\is_string($default)) {
|
||||
return wu_kses_data($default);
|
||||
// Integer
|
||||
} elseif ($this->is_numeric()) {
|
||||
return (int) $default;
|
||||
}
|
||||
// @todo datetime, decimal, and other column types
|
||||
// Unknown, so return the default's default
|
||||
return '';
|
||||
}
|
||||
/**
|
||||
* Sanitize the pattern
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param string $pattern
|
||||
* @return string
|
||||
*/
|
||||
private function sanitize_pattern($pattern = '%s')
|
||||
{
|
||||
// Allowed patterns
|
||||
$allowed_patterns = array('%s', '%d', '%f');
|
||||
// Return pattern if allowed
|
||||
if (\in_array($pattern, $allowed_patterns, \true)) {
|
||||
return $pattern;
|
||||
}
|
||||
// Fallback to digit or string
|
||||
return $this->is_numeric() ? '%d' : '%s';
|
||||
}
|
||||
/**
|
||||
* Sanitize the validation callback
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param string $callback Default empty string. A callable PHP function name or method
|
||||
* @return string The most appropriate callback function for the value
|
||||
*/
|
||||
private function sanitize_validation($callback = '')
|
||||
{
|
||||
// Return callback if it's callable
|
||||
if (\is_callable($callback)) {
|
||||
return $callback;
|
||||
}
|
||||
// UUID special column
|
||||
if (\true === $this->uuid) {
|
||||
$callback = array($this, 'validate_uuid');
|
||||
// Datetime fallback
|
||||
} elseif ($this->is_type('datetime')) {
|
||||
$callback = array($this, 'validate_datetime');
|
||||
// Decimal fallback
|
||||
} elseif ($this->is_type('decimal')) {
|
||||
$callback = array($this, 'validate_decimal');
|
||||
// Intval fallback
|
||||
} elseif ($this->is_numeric()) {
|
||||
$callback = 'intval';
|
||||
}
|
||||
// Return the callback
|
||||
return $callback;
|
||||
}
|
||||
/** Public Validators *****************************************************/
|
||||
/**
|
||||
* Fallback to validate a datetime value if no other is set.
|
||||
*
|
||||
* This assumes NO_ZERO_DATES is off or overridden.
|
||||
*
|
||||
* If MySQL drops support for zero dates, this method will need to be
|
||||
* updated to support different default values based on the environment.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param string $value Default ''. A datetime value that needs validating
|
||||
* @return string A valid datetime value
|
||||
*/
|
||||
public function validate_datetime($value = '')
|
||||
{
|
||||
// Handle "empty" values
|
||||
if (empty($value) || '0000-00-00 00:00:00' === $value) {
|
||||
$value = !empty($this->default) ? $this->default : '';
|
||||
// Convert to MySQL datetime format via gmdate() && strtotime
|
||||
} elseif (\function_exists('gmdate')) {
|
||||
$value = \gmdate('Y-m-d H:i:s', \strtotime($value));
|
||||
}
|
||||
// Return the validated value
|
||||
return $value;
|
||||
}
|
||||
/**
|
||||
* Validate a decimal
|
||||
*
|
||||
* (Recommended decimal column length is '18,9'.)
|
||||
*
|
||||
* This is used to validate a mixed value before it is saved into a decimal
|
||||
* column in a database table.
|
||||
*
|
||||
* Uses number_format() which does rounding to the last decimal if your
|
||||
* value is longer than specified.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param mixed $value Default empty string. The decimal value to validate
|
||||
* @param int $decimals Default 9. The number of decimal points to accept
|
||||
* @return float
|
||||
*/
|
||||
public function validate_decimal($value = 0, $decimals = 9)
|
||||
{
|
||||
// Protect against non-numeric values
|
||||
if (!\is_numeric($value)) {
|
||||
$value = 0;
|
||||
}
|
||||
// Protect against non-numeric decimals
|
||||
if (!\is_numeric($decimals)) {
|
||||
$decimals = 9;
|
||||
}
|
||||
// Is the value negative?
|
||||
$negative_exponent = $value < 0 ? -1 : 1;
|
||||
// Only numbers and period
|
||||
$value = \preg_replace('/[^0-9\\.]/', '', (string) $value);
|
||||
// Format to number of decimals, and cast as float
|
||||
$formatted = \number_format($value, $decimals, '.', '');
|
||||
// Adjust for negative values
|
||||
$retval = $formatted * $negative_exponent;
|
||||
// Return
|
||||
return $retval;
|
||||
}
|
||||
/**
|
||||
* Validate a UUID.
|
||||
*
|
||||
* This uses the v4 algorithm to generate a UUID that is used to uniquely
|
||||
* and universally identify a given database row without any direct
|
||||
* connection or correlation to the data in that row.
|
||||
*
|
||||
* From http://php.net/manual/en/function.uniqid.php#94959
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @param string $value The UUID value (empty on insert, string on update)
|
||||
* @return string Generated UUID.
|
||||
*/
|
||||
public function validate_uuid($value = '')
|
||||
{
|
||||
// Default URN UUID prefix
|
||||
$prefix = 'urn:uuid:';
|
||||
// Bail if not empty and correctly prefixed
|
||||
// (UUIDs should _never_ change once they are set)
|
||||
if (!empty($value) && 0 === \strpos($value, $prefix)) {
|
||||
return $value;
|
||||
}
|
||||
// Put the pieces together
|
||||
$value = \sprintf(
|
||||
"{$prefix}%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
|
||||
// 32 bits for "time_low"
|
||||
\mt_rand(0, 0xffff),
|
||||
\mt_rand(0, 0xffff),
|
||||
// 16 bits for "time_mid"
|
||||
\mt_rand(0, 0xffff),
|
||||
// 16 bits for "time_hi_and_version",
|
||||
// four most significant bits holds version number 4
|
||||
\mt_rand(0, 0xfff) | 0x4000,
|
||||
// 16 bits, 8 bits for "clk_seq_hi_res",
|
||||
// 8 bits for "clk_seq_low",
|
||||
// two most significant bits holds zero and one for variant DCE1.1
|
||||
\mt_rand(0, 0x3fff) | 0x8000,
|
||||
// 48 bits for "node"
|
||||
\mt_rand(0, 0xffff),
|
||||
\mt_rand(0, 0xffff),
|
||||
\mt_rand(0, 0xffff)
|
||||
);
|
||||
// Return the new UUID
|
||||
return $value;
|
||||
}
|
||||
/** Table Helpers *********************************************************/
|
||||
/**
|
||||
* Return a string representation of what this column's properties look like
|
||||
* in a MySQL.
|
||||
*
|
||||
* @todo
|
||||
* @since 1.0.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_create_string()
|
||||
{
|
||||
// Default return val
|
||||
$retval = '';
|
||||
// Bail if no name
|
||||
if (!empty($this->name)) {
|
||||
$retval .= $this->name;
|
||||
}
|
||||
// Type
|
||||
if (!empty($this->type)) {
|
||||
$retval .= " {$this->type}";
|
||||
}
|
||||
// Length
|
||||
if (!empty($this->length)) {
|
||||
$retval .= '(' . $this->length . ')';
|
||||
}
|
||||
// Unsigned
|
||||
if (!empty($this->unsigned)) {
|
||||
$retval .= " unsigned";
|
||||
}
|
||||
// Zerofill
|
||||
if (!empty($this->zerofill)) {
|
||||
// TBD
|
||||
}
|
||||
// Binary
|
||||
if (!empty($this->binary)) {
|
||||
// TBD
|
||||
}
|
||||
// Allow null
|
||||
if (!empty($this->allow_null)) {
|
||||
$retval .= " NOT NULL ";
|
||||
}
|
||||
// Default
|
||||
if (!empty($this->default)) {
|
||||
$retval .= " default '{$this->default}'";
|
||||
// A literal false means no default value
|
||||
} elseif (\false !== $this->default) {
|
||||
// Numeric
|
||||
if ($this->is_numeric()) {
|
||||
$retval .= " default '0'";
|
||||
} elseif ($this->is_type('datetime')) {
|
||||
$retval .= " default '0000-00-00 00:00:00'";
|
||||
} else {
|
||||
$retval .= " default ''";
|
||||
}
|
||||
}
|
||||
// Extra
|
||||
if (!empty($this->extra)) {
|
||||
$retval .= " {$this->extra}";
|
||||
}
|
||||
// Encoding
|
||||
if (!empty($this->encoding)) {
|
||||
} else {
|
||||
}
|
||||
// Collation
|
||||
if (!empty($this->collation)) {
|
||||
} else {
|
||||
}
|
||||
// Return the create string
|
||||
return $retval;
|
||||
}
|
||||
}
|
131
dependencies/berlindb/core/src/Database/Queries/Compare.php
vendored
Normal file
131
dependencies/berlindb/core/src/Database/Queries/Compare.php
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Base Custom Database Table Compare Query Class.
|
||||
*
|
||||
* @package Database
|
||||
* @subpackage Compare
|
||||
* @copyright Copyright (c) 2021
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
* @since 1.0.0
|
||||
*/
|
||||
namespace WP_Ultimo\Dependencies\BerlinDB\Database\Queries;
|
||||
|
||||
// Exit if accessed directly
|
||||
\defined('ABSPATH') || exit;
|
||||
/**
|
||||
* Class used for generating SQL for compare clauses.
|
||||
*
|
||||
* This class is used to generate the SQL when a `compare` argument is passed to
|
||||
* the `Base` query class. It extends `Meta` so the `compare` key accepts
|
||||
* the same parameters as the ones passed to `Meta`.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Compare extends Meta
|
||||
{
|
||||
// All supported SQL comparisons
|
||||
const ALL_COMPARES = array('=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN', 'EXISTS', 'NOT EXISTS', 'REGEXP', 'NOT REGEXP', 'RLIKE');
|
||||
// IN and BETWEEN
|
||||
const IN_BETWEEN_COMPARES = array('IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN');
|
||||
/**
|
||||
* Generate SQL WHERE clauses for a first-order query clause.
|
||||
*
|
||||
* "First-order" means that it's an array with a 'key' or 'value'.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array $clause Query clause (passed by reference).
|
||||
* @param array $parent_query Parent query array.
|
||||
* @param string $clause_key Optional. The array key used to name the clause in the original `$meta_query`
|
||||
* parameters. If not provided, a key will be generated automatically.
|
||||
* @return array {
|
||||
* Array containing WHERE SQL clauses to append to a first-order query.
|
||||
*
|
||||
* @type string $where SQL fragment to append to the main WHERE clause.
|
||||
* }
|
||||
*/
|
||||
public function get_sql_for_clause(&$clause, $parent_query, $clause_key = '')
|
||||
{
|
||||
global $wpdb;
|
||||
// Default chunks
|
||||
$sql_chunks = array('where' => array(), 'join' => array());
|
||||
// Maybe format compare clause
|
||||
if (isset($clause['compare'])) {
|
||||
$clause['compare'] = \strtoupper($clause['compare']);
|
||||
// Or set compare clause based on value
|
||||
} else {
|
||||
$clause['compare'] = isset($clause['value']) && \is_array($clause['value']) ? 'IN' : '=';
|
||||
}
|
||||
// Fallback to equals
|
||||
if (!\in_array($clause['compare'], self::ALL_COMPARES, \true)) {
|
||||
$clause['compare'] = '=';
|
||||
}
|
||||
// Uppercase or equals
|
||||
if (isset($clause['compare_key']) && 'LIKE' === \strtoupper($clause['compare_key'])) {
|
||||
$clause['compare_key'] = \strtoupper($clause['compare_key']);
|
||||
} else {
|
||||
$clause['compare_key'] = '=';
|
||||
}
|
||||
// Get comparison from clause
|
||||
$compare = $clause['compare'];
|
||||
/** Build the WHERE clause ********************************************/
|
||||
// Column name and value.
|
||||
if (\array_key_exists('key', $clause) && \array_key_exists('value', $clause)) {
|
||||
$column = sanitize_key($clause['key']);
|
||||
$value = $clause['value'];
|
||||
// IN or BETWEEN
|
||||
if (\in_array($compare, self::IN_BETWEEN_COMPARES, \true)) {
|
||||
if (!\is_array($value)) {
|
||||
$value = \preg_split('/[,\\s]+/', $value);
|
||||
}
|
||||
// Anything else
|
||||
} else {
|
||||
$value = \trim($value);
|
||||
}
|
||||
// Format WHERE from compare value(s)
|
||||
switch ($compare) {
|
||||
case 'IN':
|
||||
case 'NOT IN':
|
||||
$compare_string = '(' . \substr(\str_repeat(',%s', \count($value)), 1) . ')';
|
||||
$where = $wpdb->prepare($compare_string, $value);
|
||||
break;
|
||||
case 'BETWEEN':
|
||||
case 'NOT BETWEEN':
|
||||
$value = \array_slice($value, 0, 2);
|
||||
$where = $wpdb->prepare('%s AND %s', $value);
|
||||
break;
|
||||
case 'LIKE':
|
||||
case 'NOT LIKE':
|
||||
$value = '%' . $wpdb->esc_like($value) . '%';
|
||||
$where = $wpdb->prepare('%s', $value);
|
||||
break;
|
||||
// EXISTS with a value is interpreted as '='.
|
||||
case 'EXISTS':
|
||||
$compare = '=';
|
||||
$where = $wpdb->prepare('%s', $value);
|
||||
break;
|
||||
// 'value' is ignored for NOT EXISTS.
|
||||
case 'NOT EXISTS':
|
||||
$where = '';
|
||||
break;
|
||||
default:
|
||||
$where = $wpdb->prepare('%s', $value);
|
||||
break;
|
||||
}
|
||||
// Maybe add column, compare, & where to chunks
|
||||
if (!empty($where)) {
|
||||
$sql_chunks['where'][] = "{$column} {$compare} {$where}";
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Multiple WHERE clauses (for meta_key and meta_value) should
|
||||
* be joined in parentheses.
|
||||
*/
|
||||
if (1 < \count($sql_chunks['where'])) {
|
||||
$sql_chunks['where'] = array('( ' . \implode(' AND ', $sql_chunks['where']) . ' )');
|
||||
}
|
||||
// Return
|
||||
return $sql_chunks;
|
||||
}
|
||||
}
|
1017
dependencies/berlindb/core/src/Database/Queries/Date.php
vendored
Normal file
1017
dependencies/berlindb/core/src/Database/Queries/Date.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
28
dependencies/berlindb/core/src/Database/Queries/Meta.php
vendored
Normal file
28
dependencies/berlindb/core/src/Database/Queries/Meta.php
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Base Custom Database Table Meta Query Class.
|
||||
*
|
||||
* @package Database
|
||||
* @subpackage Meta
|
||||
* @copyright Copyright (c) 2021
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
* @since 1.1.0
|
||||
*/
|
||||
namespace WP_Ultimo\Dependencies\BerlinDB\Database\Queries;
|
||||
|
||||
// Exit if accessed directly
|
||||
\defined('ABSPATH') || exit;
|
||||
// @todo Remove the need for this dependency
|
||||
use \WP_Meta_Query;
|
||||
/**
|
||||
* Class for generating SQL clauses that filter a primary query according to meta.
|
||||
*
|
||||
* It currently extends the WP_Meta_Query class in WordPress, but in the future
|
||||
* will be derived completely from other registered tables.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
class Meta extends WP_Meta_Query
|
||||
{
|
||||
}
|
2589
dependencies/berlindb/core/src/Database/Query.php
vendored
Normal file
2589
dependencies/berlindb/core/src/Database/Query.php
vendored
Normal file
File diff suppressed because it is too large
Load Diff
66
dependencies/berlindb/core/src/Database/Row.php
vendored
Normal file
66
dependencies/berlindb/core/src/Database/Row.php
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Base Custom Database Table Row Class.
|
||||
*
|
||||
* @package Database
|
||||
* @subpackage Row
|
||||
* @copyright Copyright (c) 2021
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
* @since 1.0.0
|
||||
*/
|
||||
namespace WP_Ultimo\Dependencies\BerlinDB\Database;
|
||||
|
||||
// Exit if accessed directly
|
||||
\defined('ABSPATH') || exit;
|
||||
/**
|
||||
* Base database row class.
|
||||
*
|
||||
* This class exists solely for other classes to extend (and to encapsulate
|
||||
* database schema changes for those objects) to help separate the needs of the
|
||||
* application layer from the requirements of the database layer.
|
||||
*
|
||||
* For example, if a database column is renamed or a return value needs to be
|
||||
* formatted differently, this class will make sure old values are still
|
||||
* supported and new values do not conflict.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Row extends Base
|
||||
{
|
||||
/**
|
||||
* Construct a database object.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param mixed Null by default, Array/Object if not
|
||||
*/
|
||||
public function __construct($item = null)
|
||||
{
|
||||
if (!empty($item)) {
|
||||
$this->init($item);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Initialize class properties based on data array.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param array $data
|
||||
*/
|
||||
private function init($data = array())
|
||||
{
|
||||
$this->set_vars($data);
|
||||
}
|
||||
/**
|
||||
* Determines whether the current row exists.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists()
|
||||
{
|
||||
return !empty($this->id);
|
||||
}
|
||||
}
|
81
dependencies/berlindb/core/src/Database/Schema.php
vendored
Normal file
81
dependencies/berlindb/core/src/Database/Schema.php
vendored
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Base Custom Database Table Schema Class.
|
||||
*
|
||||
* @package Database
|
||||
* @subpackage Schema
|
||||
* @copyright Copyright (c) 2021
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
* @since 1.0.0
|
||||
*/
|
||||
namespace WP_Ultimo\Dependencies\BerlinDB\Database;
|
||||
|
||||
// Exit if accessed directly
|
||||
\defined('ABSPATH') || exit;
|
||||
/**
|
||||
* A base database table schema class, which houses the collection of columns
|
||||
* that a table is made out of.
|
||||
*
|
||||
* This class is intended to be extended for each unique database table,
|
||||
* including global tables for multisite, and users tables.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Schema extends Base
|
||||
{
|
||||
/**
|
||||
* Array of database column objects to turn into Column.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var array
|
||||
*/
|
||||
protected $columns = array();
|
||||
/**
|
||||
* Invoke new column objects based on array of column data.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Bail if no columns
|
||||
if (empty($this->columns) || !\is_array($this->columns)) {
|
||||
return;
|
||||
}
|
||||
// Juggle original columns array
|
||||
$columns = $this->columns;
|
||||
$this->columns = array();
|
||||
// Loop through columns and create objects from them
|
||||
foreach ($columns as $column) {
|
||||
if (\is_array($column)) {
|
||||
$this->columns[] = new Column($column);
|
||||
} elseif ($column instanceof Column) {
|
||||
$this->columns[] = $column;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return the schema in string form.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string Calls get_create_string() on every column.
|
||||
*/
|
||||
protected function to_string()
|
||||
{
|
||||
// Default return value
|
||||
$retval = '';
|
||||
// Bail if no columns to convert
|
||||
if (empty($this->columns)) {
|
||||
return $retval;
|
||||
}
|
||||
// Loop through columns...
|
||||
foreach ($this->columns as $column_info) {
|
||||
if (\method_exists($column_info, 'get_create_string')) {
|
||||
$retval .= '\\n' . $column_info->get_create_string() . ', ';
|
||||
}
|
||||
}
|
||||
// Return the string
|
||||
return $retval;
|
||||
}
|
||||
}
|
836
dependencies/berlindb/core/src/Database/Table.php
vendored
Normal file
836
dependencies/berlindb/core/src/Database/Table.php
vendored
Normal file
@ -0,0 +1,836 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Base Custom Database Table Class.
|
||||
*
|
||||
* @package Database
|
||||
* @subpackage Table
|
||||
* @copyright Copyright (c) 2021
|
||||
* @license https://opensource.org/licenses/MIT MIT
|
||||
* @since 1.0.0
|
||||
*/
|
||||
namespace WP_Ultimo\Dependencies\BerlinDB\Database;
|
||||
|
||||
// Exit if accessed directly
|
||||
\defined('ABSPATH') || exit;
|
||||
/**
|
||||
* A base database table class, which facilitates the creation of (and schema
|
||||
* changes to) individual database tables.
|
||||
*
|
||||
* This class is intended to be extended for each unique database table,
|
||||
* including global tables for multisite, and users tables.
|
||||
*
|
||||
* It exists to make managing database tables as easy as possible.
|
||||
*
|
||||
* Extending this class comes with several automatic benefits:
|
||||
* - Activation hook makes it great for plugins
|
||||
* - Tables store their versions in the database independently
|
||||
* - Tables upgrade via independent upgrade abstract methods
|
||||
* - Multisite friendly - site tables switch on "switch_blog" action
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
abstract class Table extends Base
|
||||
{
|
||||
/**
|
||||
* Table name, without the global table prefix.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $name = '';
|
||||
/**
|
||||
* Optional description.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '';
|
||||
/**
|
||||
* Database version.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var mixed
|
||||
*/
|
||||
protected $version = '';
|
||||
/**
|
||||
* Is this table for a site, or global.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var bool
|
||||
*/
|
||||
protected $global = \false;
|
||||
/**
|
||||
* Database version key (saved in _options or _sitemeta)
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $db_version_key = '';
|
||||
/**
|
||||
* Current database version.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var mixed
|
||||
*/
|
||||
protected $db_version = 0;
|
||||
/**
|
||||
* Table prefix, including the site prefix.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $table_prefix = '';
|
||||
/**
|
||||
* Table name.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $table_name = '';
|
||||
/**
|
||||
* Table name, prefixed from the base.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $prefixed_name = '';
|
||||
/**
|
||||
* Table schema.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $schema = '';
|
||||
/**
|
||||
* Database character-set & collation for table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var string
|
||||
*/
|
||||
protected $charset_collation = '';
|
||||
/**
|
||||
* Key => value array of versions => methods.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @var array
|
||||
*/
|
||||
protected $upgrades = array();
|
||||
/** Methods ***************************************************************/
|
||||
/**
|
||||
* Hook into queries, admin screens, and more!
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Setup the database table
|
||||
$this->setup();
|
||||
// Bail if setup failed
|
||||
if (empty($this->name) || empty($this->db_version_key)) {
|
||||
return;
|
||||
}
|
||||
// Add the table to the database interface
|
||||
$this->set_db_interface();
|
||||
// Set the database schema
|
||||
$this->set_schema();
|
||||
// Add hooks
|
||||
$this->add_hooks();
|
||||
// Maybe force upgrade if testing
|
||||
if ($this->is_testing()) {
|
||||
$this->maybe_upgrade();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Compatibility for clone() method for PHP versions less than 7.0.
|
||||
*
|
||||
* See: https://github.com/sugarcalendar/core/issues/105
|
||||
*
|
||||
* This shim will be removed at a later date.
|
||||
*
|
||||
* @since 2.0.20
|
||||
*
|
||||
* @param string $function
|
||||
* @param array $args
|
||||
*/
|
||||
public function __call($function = '', $args = array())
|
||||
{
|
||||
if ('clone' === $function) {
|
||||
\call_user_func_array(array($this, '_clone'), $args);
|
||||
}
|
||||
}
|
||||
/** Abstract **************************************************************/
|
||||
/**
|
||||
* Setup this database table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
protected abstract function set_schema();
|
||||
/** Multisite *************************************************************/
|
||||
/**
|
||||
* Update table version & references.
|
||||
*
|
||||
* Hooked to the "switch_blog" action.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param int $site_id The site being switched to
|
||||
*/
|
||||
public function switch_blog($site_id = 0)
|
||||
{
|
||||
// Update DB version based on the current site
|
||||
if (!$this->is_global()) {
|
||||
$this->db_version = get_blog_option($site_id, $this->db_version_key, \false);
|
||||
}
|
||||
// Update interface for switched site
|
||||
$this->set_db_interface();
|
||||
}
|
||||
/** Public Helpers ********************************************************/
|
||||
/**
|
||||
* Maybe upgrade the database table. Handles creation & schema changes.
|
||||
*
|
||||
* Hooked to the `admin_init` action.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function maybe_upgrade()
|
||||
{
|
||||
// Bail if not upgradeable
|
||||
if (!$this->is_upgradeable()) {
|
||||
return;
|
||||
}
|
||||
// Bail if upgrade not needed
|
||||
if (!$this->needs_upgrade()) {
|
||||
return;
|
||||
}
|
||||
// Upgrade
|
||||
if ($this->exists()) {
|
||||
$this->upgrade();
|
||||
// Install
|
||||
} else {
|
||||
$this->install();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return whether this table needs an upgrade.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param mixed $version Database version to check if upgrade is needed
|
||||
*
|
||||
* @return bool True if table needs upgrading. False if not.
|
||||
*/
|
||||
public function needs_upgrade($version = \false)
|
||||
{
|
||||
// Use the current table version if none was passed
|
||||
if (empty($version)) {
|
||||
$version = $this->version;
|
||||
}
|
||||
// Get the current database version
|
||||
$this->get_db_version();
|
||||
// Is the database table up to date?
|
||||
$is_current = \version_compare($this->db_version, $version, '>=');
|
||||
// Return false if current, true if out of date
|
||||
return \true === $is_current ? \false : \true;
|
||||
}
|
||||
/**
|
||||
* Return whether this table can be upgraded.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool True if table can be upgraded. False if not.
|
||||
*/
|
||||
public function is_upgradeable()
|
||||
{
|
||||
// Bail if global and upgrading global tables is not allowed
|
||||
if ($this->is_global() && !wp_should_upgrade_global_tables()) {
|
||||
return \false;
|
||||
}
|
||||
// Kinda weird, but assume it is
|
||||
return \true;
|
||||
}
|
||||
/**
|
||||
* Return the current table version from the database.
|
||||
*
|
||||
* This is public method for accessing a private variable so that it cannot
|
||||
* be externally modified.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_version()
|
||||
{
|
||||
$this->get_db_version();
|
||||
return $this->db_version;
|
||||
}
|
||||
/**
|
||||
* Install a database table
|
||||
*
|
||||
* Creates the table and sets the version information if successful.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function install()
|
||||
{
|
||||
// Try to create the table
|
||||
$created = $this->create();
|
||||
// Set the DB version if create was successful
|
||||
if (\true === $created) {
|
||||
$this->set_db_version();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Uninstall a database table
|
||||
*
|
||||
* Drops the table and deletes the version information if successful and/or
|
||||
* the table does not exist anymore.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public function uninstall()
|
||||
{
|
||||
// Try to drop the table
|
||||
$dropped = $this->drop();
|
||||
// Delete the DB version if drop was successful or table does not exist
|
||||
if (\true === $dropped || !$this->exists()) {
|
||||
$this->delete_db_version();
|
||||
}
|
||||
}
|
||||
/** Public Management *****************************************************/
|
||||
/**
|
||||
* Check if table already exists.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists()
|
||||
{
|
||||
// Get the database interface
|
||||
$db = $this->get_db();
|
||||
// Bail if no database interface is available
|
||||
if (empty($db)) {
|
||||
return \false;
|
||||
}
|
||||
// Query statement
|
||||
$query = "SHOW TABLES LIKE %s";
|
||||
$like = $db->esc_like($this->table_name);
|
||||
$prepared = $db->prepare($query, $like);
|
||||
$result = $db->get_var($prepared);
|
||||
// Does the table exist?
|
||||
return $this->is_success($result);
|
||||
}
|
||||
/**
|
||||
* Get columns from table.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function columns()
|
||||
{
|
||||
// Get the database interface
|
||||
$db = $this->get_db();
|
||||
// Bail if no database interface is available
|
||||
if (empty($db)) {
|
||||
return \false;
|
||||
}
|
||||
// Query statement
|
||||
$query = "SHOW FULL COLUMNS FROM {$this->table_name}";
|
||||
$result = $db->get_results($query);
|
||||
// Return the results
|
||||
return $this->is_success($result) ? $result : \false;
|
||||
}
|
||||
/**
|
||||
* Create the table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
// Get the database interface
|
||||
$db = $this->get_db();
|
||||
// Bail if no database interface is available
|
||||
if (empty($db)) {
|
||||
return \false;
|
||||
}
|
||||
// Query statement
|
||||
$query = "CREATE TABLE {$this->table_name} ( {$this->schema} ) {$this->charset_collation}";
|
||||
$result = $db->query($query);
|
||||
// Was the table created?
|
||||
return $this->is_success($result);
|
||||
}
|
||||
/**
|
||||
* Drop the database table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function drop()
|
||||
{
|
||||
// Get the database interface
|
||||
$db = $this->get_db();
|
||||
// Bail if no database interface is available
|
||||
if (empty($db)) {
|
||||
return \false;
|
||||
}
|
||||
// Query statement
|
||||
$query = "DROP TABLE {$this->table_name}";
|
||||
$result = $db->query($query);
|
||||
// Did the table get dropped?
|
||||
return $this->is_success($result);
|
||||
}
|
||||
/**
|
||||
* Truncate the database table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function truncate()
|
||||
{
|
||||
// Get the database interface
|
||||
$db = $this->get_db();
|
||||
// Bail if no database interface is available
|
||||
if (empty($db)) {
|
||||
return \false;
|
||||
}
|
||||
// Query statement
|
||||
$query = "TRUNCATE TABLE {$this->table_name}";
|
||||
$result = $db->query($query);
|
||||
// Did the table get truncated?
|
||||
return $this->is_success($result);
|
||||
}
|
||||
/**
|
||||
* Delete all items from the database table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_all()
|
||||
{
|
||||
// Get the database interface
|
||||
$db = $this->get_db();
|
||||
// Bail if no database interface is available
|
||||
if (empty($db)) {
|
||||
return \false;
|
||||
}
|
||||
// Query statement
|
||||
$query = "DELETE FROM {$this->table_name}";
|
||||
$result = $db->query($query);
|
||||
// Return the results
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* Clone this database table.
|
||||
*
|
||||
* Pair with copy().
|
||||
*
|
||||
* @since 1.1.0
|
||||
*
|
||||
* @param string $new_table_name The name of the new table, without prefix
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function _clone($new_table_name = '')
|
||||
{
|
||||
// Get the database interface
|
||||
$db = $this->get_db();
|
||||
// Bail if no database interface is available
|
||||
if (empty($db)) {
|
||||
return \false;
|
||||
}
|
||||
// Sanitize the new table name
|
||||
$table_name = $this->sanitize_table_name($new_table_name);
|
||||
// Bail if new table name is invalid
|
||||
if (empty($table_name)) {
|
||||
return \false;
|
||||
}
|
||||
// Query statement
|
||||
$table = $this->apply_prefix($table_name);
|
||||
$query = "CREATE TABLE {$table} LIKE {$this->table_name}";
|
||||
$result = $db->query($query);
|
||||
// Did the table get cloned?
|
||||
return $this->is_success($result);
|
||||
}
|
||||
/**
|
||||
* Copy the contents of this table to a new table.
|
||||
*
|
||||
* Pair with clone().
|
||||
*
|
||||
* @since 1.1.0
|
||||
*
|
||||
* @param string $new_table_name The name of the new table, without prefix
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function copy($new_table_name = '')
|
||||
{
|
||||
// Get the database interface
|
||||
$db = $this->get_db();
|
||||
// Bail if no database interface is available
|
||||
if (empty($db)) {
|
||||
return \false;
|
||||
}
|
||||
// Sanitize the new table name
|
||||
$table_name = $this->sanitize_table_name($new_table_name);
|
||||
// Bail if new table name is invalid
|
||||
if (empty($table_name)) {
|
||||
return \false;
|
||||
}
|
||||
// Query statement
|
||||
$table = $this->apply_prefix($table_name);
|
||||
$query = "INSERT INTO {$table} SELECT * FROM {$this->table_name}";
|
||||
$result = $db->query($query);
|
||||
// Did the table get copied?
|
||||
return $this->is_success($result);
|
||||
}
|
||||
/**
|
||||
* Count the number of items in the database table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
// Get the database interface
|
||||
$db = $this->get_db();
|
||||
// Bail if no database interface is available
|
||||
if (empty($db)) {
|
||||
return 0;
|
||||
}
|
||||
// Query statement
|
||||
$query = "SELECT COUNT(*) FROM {$this->table_name}";
|
||||
$result = $db->get_var($query);
|
||||
// Query success/fail
|
||||
return \intval($result);
|
||||
}
|
||||
/**
|
||||
* Check if column already exists.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $name Value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function column_exists($name = '')
|
||||
{
|
||||
// Get the database interface
|
||||
$db = $this->get_db();
|
||||
// Bail if no database interface is available
|
||||
if (empty($db)) {
|
||||
return \false;
|
||||
}
|
||||
// Query statement
|
||||
$query = "SHOW COLUMNS FROM {$this->table_name} LIKE %s";
|
||||
$like = $db->esc_like($name);
|
||||
$prepared = $db->prepare($query, $like);
|
||||
$result = $db->query($prepared);
|
||||
// Does the column exist?
|
||||
return $this->is_success($result);
|
||||
}
|
||||
/**
|
||||
* Check if index already exists.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $name Value
|
||||
* @param string $column Column name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function index_exists($name = '', $column = 'Key_name')
|
||||
{
|
||||
// Get the database interface
|
||||
$db = $this->get_db();
|
||||
// Bail if no database interface is available
|
||||
if (empty($db)) {
|
||||
return \false;
|
||||
}
|
||||
// Limit $column to Key or Column name, until we can do better
|
||||
if (!\in_array($column, array('Key_name', 'Column_name'), \true)) {
|
||||
$column = 'Key_name';
|
||||
}
|
||||
// Query statement
|
||||
$query = "SHOW INDEXES FROM {$this->table_name} WHERE {$column} LIKE %s";
|
||||
$like = $db->esc_like($name);
|
||||
$prepared = $db->prepare($query, $like);
|
||||
$result = $db->query($prepared);
|
||||
// Does the index exist?
|
||||
return $this->is_success($result);
|
||||
}
|
||||
/** Upgrades **************************************************************/
|
||||
/**
|
||||
* Upgrade this database table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function upgrade()
|
||||
{
|
||||
// Get pending upgrades
|
||||
$upgrades = $this->get_pending_upgrades();
|
||||
// Bail if no upgrades
|
||||
if (empty($upgrades)) {
|
||||
$this->set_db_version();
|
||||
// Return, without failure
|
||||
return \true;
|
||||
}
|
||||
// Default result
|
||||
$result = \false;
|
||||
// Try to do the upgrades
|
||||
foreach ($upgrades as $version => $callback) {
|
||||
// Do the upgrade
|
||||
$result = $this->upgrade_to($version, $callback);
|
||||
// Bail if an error occurs, to avoid skipping upgrades
|
||||
if (!$this->is_success($result)) {
|
||||
return \false;
|
||||
}
|
||||
}
|
||||
// Success/fail
|
||||
return $this->is_success($result);
|
||||
}
|
||||
/**
|
||||
* Return array of upgrades that still need to run.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*
|
||||
* @return array Array of upgrade callbacks, keyed by their db version.
|
||||
*/
|
||||
public function get_pending_upgrades()
|
||||
{
|
||||
// Default return value
|
||||
$upgrades = array();
|
||||
// Bail if no upgrades, or no database version to compare to
|
||||
if (empty($this->upgrades) || empty($this->db_version)) {
|
||||
return $upgrades;
|
||||
}
|
||||
// Loop through all upgrades, and pick out the ones that need doing
|
||||
foreach ($this->upgrades as $version => $callback) {
|
||||
if (\true === \version_compare($version, $this->db_version, '>')) {
|
||||
$upgrades[$version] = $callback;
|
||||
}
|
||||
}
|
||||
// Return
|
||||
return $upgrades;
|
||||
}
|
||||
/**
|
||||
* Upgrade to a specific database version.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param mixed $version Database version to check if upgrade is needed
|
||||
* @param string $callback Callback function or class method to call
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function upgrade_to($version = '', $callback = '')
|
||||
{
|
||||
// Bail if no upgrade is needed
|
||||
if (!$this->needs_upgrade($version)) {
|
||||
return \false;
|
||||
}
|
||||
// Allow self-named upgrade callbacks
|
||||
if (empty($callback)) {
|
||||
$callback = $version;
|
||||
}
|
||||
// Is the callback... callable?
|
||||
$callable = $this->get_callable($callback);
|
||||
// Bail if no callable upgrade was found
|
||||
if (empty($callable)) {
|
||||
return \false;
|
||||
}
|
||||
// Do the upgrade
|
||||
$result = \call_user_func($callable);
|
||||
$success = $this->is_success($result);
|
||||
// Bail if upgrade failed
|
||||
if (\true !== $success) {
|
||||
return \false;
|
||||
}
|
||||
// Set the database version to this successful version
|
||||
$this->set_db_version($version);
|
||||
// Return success
|
||||
return \true;
|
||||
}
|
||||
/** Private ***************************************************************/
|
||||
/**
|
||||
* Setup the necessary table variables.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function setup()
|
||||
{
|
||||
// Bail if no database interface is available
|
||||
if (!$this->get_db()) {
|
||||
return;
|
||||
}
|
||||
// Sanitize the database table name
|
||||
$this->name = $this->sanitize_table_name($this->name);
|
||||
// Bail if database table name was garbage
|
||||
if (\false === $this->name) {
|
||||
return;
|
||||
}
|
||||
// Separator
|
||||
$glue = '_';
|
||||
// Setup the prefixed name
|
||||
$this->prefixed_name = $this->apply_prefix($this->name, $glue);
|
||||
// Maybe create database key
|
||||
if (empty($this->db_version_key)) {
|
||||
$this->db_version_key = \implode($glue, array(sanitize_key($this->db_global), $this->prefixed_name, 'version'));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set this table up in the database interface.
|
||||
*
|
||||
* This must be done directly because the database interface does not
|
||||
* have a common mechanism for manipulating them safely.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function set_db_interface()
|
||||
{
|
||||
// Get the database once, to avoid duplicate function calls
|
||||
$db = $this->get_db();
|
||||
// Bail if no database
|
||||
if (empty($db)) {
|
||||
return;
|
||||
}
|
||||
// Set variables for global tables
|
||||
if ($this->is_global()) {
|
||||
$site_id = 0;
|
||||
$tables = 'ms_global_tables';
|
||||
// Set variables for per-site tables
|
||||
} else {
|
||||
$site_id = null;
|
||||
$tables = 'tables';
|
||||
}
|
||||
// Set the table prefix and prefix the table name
|
||||
$this->table_prefix = $db->get_blog_prefix($site_id);
|
||||
// Get the prefixed table name
|
||||
$prefixed_table_name = "{$this->table_prefix}{$this->prefixed_name}";
|
||||
// Set the database interface
|
||||
$db->{$this->prefixed_name} = $this->table_name = $prefixed_table_name;
|
||||
// Create the array if it does not exist
|
||||
if (!isset($db->{$tables})) {
|
||||
$db->{$tables} = array();
|
||||
}
|
||||
// Add the table to the global table array
|
||||
$db->{$tables}[] = $this->prefixed_name;
|
||||
// Charset
|
||||
if (!empty($db->charset)) {
|
||||
$this->charset_collation = "DEFAULT CHARACTER SET {$db->charset}";
|
||||
}
|
||||
// Collation
|
||||
if (!empty($db->collate)) {
|
||||
$this->charset_collation .= " COLLATE {$db->collate}";
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set the database version for the table.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param mixed $version Database version to set when upgrading/creating
|
||||
*/
|
||||
private function set_db_version($version = '')
|
||||
{
|
||||
// If no version is passed during an upgrade, use the current version
|
||||
if (empty($version)) {
|
||||
$version = $this->version;
|
||||
}
|
||||
// Update the DB version
|
||||
$this->is_global() ? update_network_option(get_main_network_id(), $this->db_version_key, $version) : update_option($this->db_version_key, $version);
|
||||
// Set the DB version
|
||||
$this->db_version = $version;
|
||||
}
|
||||
/**
|
||||
* Get the table version from the database.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function get_db_version()
|
||||
{
|
||||
$this->db_version = $this->is_global() ? get_network_option(get_main_network_id(), $this->db_version_key, \false) : get_option($this->db_version_key, \false);
|
||||
}
|
||||
/**
|
||||
* Delete the table version from the database.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function delete_db_version()
|
||||
{
|
||||
$this->db_version = $this->is_global() ? delete_network_option(get_main_network_id(), $this->db_version_key) : delete_option($this->db_version_key);
|
||||
}
|
||||
/**
|
||||
* Add class hooks to the parent application actions.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
private function add_hooks()
|
||||
{
|
||||
// Add table to the global database object
|
||||
add_action('switch_blog', array($this, 'switch_blog'));
|
||||
add_action('admin_init', array($this, 'maybe_upgrade'));
|
||||
}
|
||||
/**
|
||||
* Check if the current request is from some kind of test.
|
||||
*
|
||||
* This is primarily used to skip 'admin_init' and force-install tables.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_testing()
|
||||
{
|
||||
return (bool) (\defined('WP_TESTS_DIR') && WP_TESTS_DIR) || \function_exists('_manually_load_plugin');
|
||||
}
|
||||
/**
|
||||
* Check if table is global.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_global()
|
||||
{
|
||||
return \true === $this->global;
|
||||
}
|
||||
/**
|
||||
* Try to get a callable upgrade, with some magic to avoid needing to
|
||||
* do this dance repeatedly inside subclasses.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param string $callback
|
||||
*
|
||||
* @return mixed Callable string, or false if not callable
|
||||
*/
|
||||
private function get_callable($callback = '')
|
||||
{
|
||||
// Default return value
|
||||
$callable = $callback;
|
||||
// Look for global function
|
||||
if (!\is_callable($callable)) {
|
||||
// Fallback to local class method
|
||||
$callable = array($this, $callback);
|
||||
if (!\is_callable($callable)) {
|
||||
// Fallback to class method prefixed with "__"
|
||||
$callable = array($this, "__{$callback}");
|
||||
if (!\is_callable($callable)) {
|
||||
$callable = \false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Return callable string, or false if not callable
|
||||
return $callable;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user