966 lines
24 KiB
PHP
966 lines
24 KiB
PHP
<?php
|
|
/**
|
|
* Base Custom Database Table Column Class.
|
|
*
|
|
* @package Database
|
|
* @subpackage Column
|
|
* @copyright Copyright (c) 2020
|
|
* @license https://opensource.org/licenses/gpl-2.0.php GNU Public License
|
|
* @since 1.0.0
|
|
*/
|
|
namespace EDD\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' => 'wp_kses_data',
|
|
'encoding' => 'wp_kses_data',
|
|
'collation' => 'wp_kses_data',
|
|
'comment' => 'wp_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 wp_kses_data( $default );
|
|
|
|
// Integer
|
|
} elseif ( $this->is_numeric( $default ) ) {
|
|
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 mixed $pattern
|
|
* @return string
|
|
*/
|
|
private function sanitize_pattern( $pattern = false ) {
|
|
|
|
// 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 date() && strtotime
|
|
} elseif ( function_exists( 'date' ) ) {
|
|
$value = date( '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, 0x0fff ) | 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;
|
|
}
|
|
}
|