LLMS_Abstract_Database_Store
WPDB database interactions abstract class
Source Source
File: includes/abstracts/llms.abstract.database.store.php
abstract class LLMS_Abstract_Database_Store {
/**
* The Database ID of the record
*
* @var int
*/
protected $id = null;
/**
* Object properties
*
* @var array
*/
private $data = array();
/**
* Column name of the record's "created" date
*
* This can be set to an empty string if the extending
* class does not utilize or require created date storage.
*
* @var string
*/
protected $date_created = 'created';
/**
* Column name of the record's "updated" date
*
* This can be set to an empty string if the extending
* class does not utilize or require updated date storage.
*
* @var string
*/
protected $date_updated = 'updated';
/**
* Array of table column name => format
*
* @var array
*/
protected $columns = array();
/**
* Primary Key column name => format
*
* @var array
*/
protected $primary_key = array(
'id' => '%d',
);
/**
* Database Table Name
*
* @var string
*/
protected $table = '';
/**
* Database Table Prefix
*
* @var string
*/
protected $table_prefix = 'lifterlms_';
/**
* The record type
*
* Used for filters/actions.
*
* This is a placeholder which should be redefined in any extending classes.
*
* @var string
*/
protected $type = '_db_record_';
/**
* Constructor
*
* @since 3.14.0
* @since 3.21.0 Unknown.
*
* @return void
*/
public function __construct() {
if ( ! $this->id ) {
// If created dates supported, add current time to the data on construction.
if ( $this->date_created ) {
$this->set( $this->date_created, llms_current_time( 'mysql' ), false );
}
if ( $this->date_updated ) {
$this->set( $this->date_updated, llms_current_time( 'mysql' ), false );
}
}
}
/**
* Get object data
*
* @since 3.14.0
*
* @param string $key Key to retrieve.
* @return mixed
*/
public function __get( $key ) {
return $this->data[ $key ];
}
/**
* Determine if the item exists in the database
*
* @since 3.14.7
* @since 3.15.0 Unknown.
*
* @return boolean
*/
public function exists() {
if ( $this->primary_key ) {
return $this->read( $this->get_primary_key() ) ? true : false;
}
return false;
}
/**
* Get object data
*
* @since 3.14.0
* @since 3.16.0 Unknown.
* @since 3.36.0 Prevent undefined index error when attempting to retrieve an unset value from an unsaved object.
*
* @param string $key Key to retrieve.
* @param boolean $cache If true, save data to to the object for future gets.
* @return mixed
*/
public function get( $key, $cache = true ) {
$key_exists = isset( $this->data[ $key ] );
if ( ! $key_exists && $this->id ) {
$res = $this->read( $key )[ $key ];
if ( $cache ) {
$this->set( $key, $res );
}
return $res;
}
return $key_exists ? $this->$key : null;
}
/**
* Set object data
*
* @since 3.14.0
*
* @param string $key Column name.
* @param mixed $val Column value.
* @return void
*/
public function __set( $key, $val ) {
$this->data[ $key ] = $val;
}
/**
* General setter
*
* @since 3.14.0
* @since 3.21.0 Unknown.
*
* @param string $key Column name.
* @param mixed $val Column value.
* @param boolean $save If true, immediately persists to database.
* @return LLMS_Abstract_Database_Store Instance of the current object, useful for chaining.
*/
public function set( $key, $val, $save = false ) {
$this->$key = $val;
if ( $save ) {
$update = array(
$key => $val,
);
// If update date supported, add an updated date.
if ( $this->date_updated ) {
$update[ $this->date_updated ] = llms_current_time( 'mysql' );
}
$this->update( $update );
}
return $this;
}
/**
* Setup an object with an array of data
*
* @since 3.14.0
* @since 3.33.0 Return self for chaining instead of void.
*
* @param array $data key => val
* @return LLMS_Abstract_Database_Store Instance of the current object, useful for chaining.
*/
public function setup( $data ) {
foreach ( $data as $key => $val ) {
$this->set( $key, $val, false );
}
return $this;
}
/**
* Create the item in the database
*
* @since 3.14.0
* @since 3.24.0 Unknown.
* @since 4.3.0 Added deprecated hook call to `llms__created` action to preserve backwards compatibility.
* @since 6.0.0 Removed deprecated `llms__created` action hook.
*
* @return int|false Record ID on success, false on error or when there's nothing to save.
*/
private function create() {
if ( ! $this->data ) {
return false;
}
global $wpdb;
$format = array_map( array( $this, 'get_column_format' ), array_keys( $this->data ) );
$res = $wpdb->insert( $this->get_table(), $this->data, $format ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
if ( 1 === $res ) {
$this->id = $wpdb->insert_id;
/**
* Fires when a new database record is created.
*
* The dynamic portion of this hook, `$this->type`, refers to the record type.
*
* @since Unknown.
*
* @param int $id Record ID.
* @param LLMS_Abstract_Database_Store $obj Instance of the record object.
*/
do_action( "llms_{$this->type}_created", $this->id, $this );
return $this->id;
}
return false;
}
/**
* Delete the object from the database
*
* @since 3.14.0
* @since 3.24.0 Unknown.
* @since 4.3.0 Added deprecated hook call to `llms__deleted` action to preserve backwards compatibility.
* @since 6.0.0 Removed deprecated `llms__deleted` action hook.
*
* @return boolean `true` on success, `false` otherwise.
*/
public function delete() {
if ( ! $this->id ) {
return false;
}
$id = $this->id;
global $wpdb;
$where = array_combine( array_keys( $this->primary_key ), array( $this->id ) );
$res = $wpdb->delete( $this->get_table(), $where, array_values( $this->primary_key ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
if ( $res ) {
$this->id = null;
$this->data = array();
/**
* Fires when a new database record is created.
*
* The dynamic portion of this hook, `$this->type`, refers to the record type.
*
* @since Unknown.
*
* @param int $id Record ID.
* @param LLMS_Abstract_Database_Store $obj Instance of the record object.
*/
do_action( "llms_{$this->type}_deleted", $id, $this );
return true;
}
return false;
}
/**
* Read object data from the database
*
* @since 3.14.0
*
* @param string[]|string $keys Key name (or array of keys) to retrieve from the database.
* @return array|false Returns a key=>val array of data or `false` when record not found.
*/
private function read( $keys ) {
global $wpdb;
if ( is_array( $keys ) ) {
$keys = implode( ', ', $keys );
}
$res = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
$wpdb->prepare( "SELECT {$keys} FROM {$this->get_table()} WHERE {$this->get_primary_key()} = %d", $this->id ), // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- This query is safe.
ARRAY_A
);
return ! $res ? false : $res;
}
/**
* Update object data in the database
*
* @since 3.14.0
* @since 3.24.0 Unknown.
* @since 4.3.0 Added deprecated hook call to `llms__updated` action to preserve backwards compatibility.
* @since 6.0.0 Removed deprecated `llms__updated` action hook.
*
* @param array $data Data to update as key=>val.
* @return boolean
*/
private function update( $data ) {
global $wpdb;
$format = array_map( array( $this, 'get_column_format' ), array_keys( $data ) );
$where = array_combine( array_keys( $this->primary_key ), array( $this->id ) );
$res = $wpdb->update( $this->get_table(), $data, $where, $format, array_values( $this->primary_key ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
if ( $res ) {
/**
* Fires when a new database record is updated.
*
* The dynamic portion of this hook, `$this->type`, refers to the record type.
*
* @since Unknown.
*
* @param int $id Record ID.
* @param LLMS_Abstract_Database_Store $obj Instance of the record object.
*/
do_action( "llms_{$this->type}_updated", $this->id, $this );
return true;
}
return false;
}
/**
* Load the whole object from the database
*
* @since 3.14.0
*
* @return LLMS_Abstract_Database_Store instance of the current object, useful for chaining.
*/
protected function hydrate() {
if ( $this->id ) {
$res = $this->read( array_keys( $this->columns ) );
if ( $res ) {
$this->data = array_merge( $this->data, $res );
}
}
return $this;
}
/**
* Save object to the database
*
* Creates it if doesn't already exist, updates if it does.
*
* @since 3.14.0
* @since 3.24.0 Unknown.
*
* @return boolean
*/
public function save() {
if ( ! $this->id ) {
$id = $this->create();
if ( $id ) {
return true;
}
return false;
} else {
return $this->update( $this->data );
}
}
/**
* Retrieve the format for a column
*
* @since 3.14.0
*
* @param string $key Column name.
* @return string
*/
private function get_column_format( $key ) {
if ( isset( $this->columns[ $key ] ) ) {
return $this->columns[ $key ];
}
return '%s';
}
/**
* Retrieve the primary key column name
*
* @since 3.15.0
*
* @return string
*/
protected function get_primary_key() {
$primary_key = array_keys( $this->primary_key );
return preg_replace( '/[^a-zA-Z0-9_]/', '', $primary_key[0] );
}
/**
* Get the ID of the object
*
* @since 3.14.0
*
* @return int
*/
public function get_id() {
return $this->id;
}
/**
* Get the table Name
*
* @since 3.14.0
*
* @return string
*/
private function get_table() {
global $wpdb;
return $wpdb->prefix . $this->table_prefix . $this->table;
}
/**
* Retrieve object as an array
*
* @since 3.14.0
* @since 3.34.0 Return the item ID instead of item format as the value of the primary key.
* @since 3.36.0 Hydrate before returning the array.
*
* @return array
*/
public function to_array() {
$this->hydrate();
return array_merge( array_combine( array_keys( $this->primary_key ), array( $this->id ) ), $this->data );
}
}
Expand full source code Collapse full source code View on GitHub
Methods Methods
- __construct — Constructor
- __get — Get object data
- __set — Set object data
- create — Create the item in the database
- delete — Delete the object from the database
- exists — Determine if the item exists in the database
- get — Get object data
- get_column_format — Retrieve the format for a column
- get_id — Get the ID of the object
- get_primary_key — Retrieve the primary key column name
- get_table — Get the table Name
- hydrate — Load the whole object from the database
- read — Read object data from the database
- save — Save object to the database
- set — General setter
- setup — Setup an object with an array of data
- to_array — Retrieve object as an array
- update — Update object data in the database
Changelog Changelog
| Version | Description |
|---|---|
| 4.3.0 | Add deprecated hook calls to preserve backwards compatibility for extending classes which have no $type property declaration. Updated the $type property to have a default placeholder value. |
| 3.36.0 | Prevent undefined index error when attempting to retrieve an unset value from an unsaved object. Hydrate before returning an array via the to_array() method. |
| 3.34.0 | to_array() method returns value of the primary key instead of the format. |
| 3.33.0 | setup() method returns self instead of void. |
| 3.14.0 | Introduced. |