315 lines
6.1 KiB
PHP
315 lines
6.1 KiB
PHP
<?php
|
|
|
|
namespace AutomateWoo;
|
|
|
|
/**
|
|
* @class Model
|
|
*
|
|
* @property $id
|
|
*/
|
|
abstract class Model {
|
|
|
|
/** @var string : required for every model and must have a corresponding Database_Table */
|
|
public $table_id;
|
|
|
|
/** @var bool */
|
|
public $exists = false;
|
|
|
|
/** @var array */
|
|
public $data = [];
|
|
|
|
/** @var array - data as it last existed in the database */
|
|
public $original_data = [];
|
|
|
|
/** @var array */
|
|
public $changed_fields = [];
|
|
|
|
/** @var string */
|
|
public $object_type;
|
|
|
|
|
|
/**
|
|
* @return int
|
|
*/
|
|
public function get_id() {
|
|
return $this->id ? (int) $this->id : 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param int $id
|
|
*/
|
|
public function set_id( $id ) {
|
|
$this->id = $id;
|
|
}
|
|
|
|
|
|
/**
|
|
* Fill model with data
|
|
*
|
|
* @param array $row
|
|
*/
|
|
public function fill( $row ) {
|
|
if ( ! is_array( $row ) ) {
|
|
return;
|
|
}
|
|
|
|
$this->data = $row;
|
|
$this->original_data = $row;
|
|
$this->exists = true;
|
|
|
|
do_action( 'automatewoo/object/load', $this );
|
|
}
|
|
|
|
|
|
/**
|
|
* @param string $field
|
|
* @param string|int $value
|
|
*/
|
|
public function get_by( $field, $value ) {
|
|
|
|
global $wpdb;
|
|
|
|
$row = $wpdb->get_row(
|
|
$wpdb->prepare(
|
|
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
|
"SELECT * FROM {$this->get_table_name()} WHERE $field = %s",
|
|
$value
|
|
),
|
|
ARRAY_A
|
|
);
|
|
|
|
if ( ! $row ) {
|
|
return;
|
|
}
|
|
|
|
$this->fill( $row );
|
|
}
|
|
|
|
|
|
/**
|
|
* Magic method for accessing db fields
|
|
*
|
|
* @param string $key
|
|
* @return mixed
|
|
*/
|
|
public function __get( $key ) {
|
|
return $this->get_prop( $key );
|
|
}
|
|
|
|
|
|
/**
|
|
* Magic method for setting db fields
|
|
*
|
|
* @param string $key
|
|
* @param mixed $value
|
|
*/
|
|
public function __set( $key, $value ) {
|
|
$this->set_prop( $key, $value );
|
|
}
|
|
|
|
|
|
/**
|
|
* @param string $key
|
|
* @param mixed $value
|
|
*/
|
|
public function set_prop( $key, $value ) {
|
|
|
|
if ( is_array( $value ) && ! $value ) {
|
|
$value = ''; // convert empty arrays to blank
|
|
}
|
|
|
|
$this->data[ $key ] = $value;
|
|
$this->changed_fields[] = $key;
|
|
}
|
|
|
|
|
|
/**
|
|
* @param string $key
|
|
* @return bool
|
|
*/
|
|
public function has_prop( $key ) {
|
|
return isset( $this->data[ $key ] );
|
|
}
|
|
|
|
|
|
/**
|
|
* @param string $key
|
|
* @return mixed
|
|
*/
|
|
public function get_prop( $key ) {
|
|
if ( ! isset( $this->data[ $key ] ) ) {
|
|
return false;
|
|
}
|
|
|
|
$value = $this->data[ $key ];
|
|
$value = maybe_unserialize( $value );
|
|
|
|
return $value;
|
|
}
|
|
|
|
|
|
/**
|
|
* @return Database_Table
|
|
*/
|
|
public function get_table() {
|
|
|
|
if ( ! isset( $this->table_id ) ) {
|
|
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
|
wp_die( sprintf( 'AutomateWoo - %s is an incompatible subclass of %s. You may need need to update your AutomateWoo add-ons.', get_called_class(), __CLASS__ ) );
|
|
}
|
|
|
|
return Database_Tables::get( $this->table_id );
|
|
}
|
|
|
|
|
|
/**
|
|
* @return string
|
|
*/
|
|
public function get_table_name() {
|
|
return $this->get_table()->get_name();
|
|
}
|
|
|
|
|
|
/**
|
|
* Inserts or updates the model
|
|
* Only updates modified fields
|
|
*
|
|
* @return bool True on success, false on error.
|
|
*/
|
|
public function save() {
|
|
|
|
global $wpdb;
|
|
|
|
if ( $this->exists ) {
|
|
// update changed fields
|
|
$changed_data = array_intersect_key( $this->data, array_flip( $this->changed_fields ) );
|
|
|
|
// serialize
|
|
$changed_data = array_map( 'maybe_serialize', $changed_data );
|
|
|
|
if ( empty( $changed_data ) ) {
|
|
return true;
|
|
}
|
|
|
|
$updated = $wpdb->update(
|
|
$this->get_table_name(),
|
|
$changed_data,
|
|
[ 'id' => $this->get_id() ],
|
|
null,
|
|
[ '%d' ]
|
|
);
|
|
|
|
if ( false === $updated ) {
|
|
// Return here to prevent cache updates on error
|
|
return false;
|
|
}
|
|
|
|
do_action( 'automatewoo/object/update', $this ); // cleans object cache
|
|
} else {
|
|
$this->data = array_map( 'maybe_serialize', $this->data );
|
|
|
|
// insert row
|
|
$wpdb->insert(
|
|
$this->get_table_name(),
|
|
$this->data
|
|
);
|
|
|
|
if ( $wpdb->insert_id ) {
|
|
$this->exists = true;
|
|
$this->id = $wpdb->insert_id;
|
|
} else {
|
|
$aw_catch_db_error = 'Error: ' . $wpdb->last_error . ' (Query: ' . $wpdb->last_query . ')';
|
|
/* translators: %1$s object type, %2$s DB error message and query */
|
|
Logger::critical( 'errors', sprintf( __( 'Could not insert \'%1$s\' item to database. AutomateWoo tables may not be installed. (%2$s)', 'automatewoo' ), $this->object_type, $aw_catch_db_error ) );
|
|
|
|
// Return here to prevent cache updates on error
|
|
return false;
|
|
}
|
|
|
|
do_action( 'automatewoo/object/create', $this ); // cleans object cache
|
|
}
|
|
|
|
$this->clear_cached_data();
|
|
|
|
// reset changed data
|
|
// important to reset after cache hooks
|
|
$this->changed_fields = [];
|
|
$this->original_data = $this->data;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function delete() {
|
|
global $wpdb;
|
|
|
|
do_action( 'automatewoo/object/delete', $this ); // cleans object cache
|
|
|
|
if ( ! $this->exists ) {
|
|
return;
|
|
}
|
|
|
|
$wpdb->query(
|
|
$wpdb->prepare(
|
|
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
|
"DELETE FROM {$this->get_table_name()} WHERE id = %d",
|
|
$this->get_id()
|
|
)
|
|
);
|
|
|
|
$this->exists = false;
|
|
$this->clear_cached_data();
|
|
}
|
|
|
|
/**
|
|
* Clear cached data.
|
|
*
|
|
* @since 6.1.8
|
|
*/
|
|
public function clear_cached_data() {}
|
|
|
|
/**
|
|
* @param string $column
|
|
* @return bool|DateTime
|
|
*/
|
|
protected function get_date_column( $column ) {
|
|
if ( ! $column ) {
|
|
return false;
|
|
}
|
|
|
|
$prop = $this->get_prop( $column );
|
|
if ( ! $prop ) {
|
|
return false;
|
|
}
|
|
|
|
return new DateTime( $prop );
|
|
}
|
|
|
|
|
|
/**
|
|
* Sets the value of a date column from a mixed input.
|
|
*
|
|
* $value can be an instance of WC_DateTime the timezone will be ignored.
|
|
* If $value is a string it must be MYSQL formatted.
|
|
*
|
|
* @param string $column
|
|
* @param \WC_DateTime|DateTime|\DateTime|string|null $value
|
|
*/
|
|
protected function set_date_column( $column, $value ) {
|
|
if ( is_a( $value, 'DateTime' ) ) {
|
|
/** @var \DateTime $value Accepts AutomateWoo\DateTime, DateTime or WC_DateTime */
|
|
// convert to UTC time
|
|
$utc_date = new DateTime();
|
|
$utc_date->setTimestamp( $value->getTimestamp() );
|
|
$this->set_prop( $column, $utc_date->to_mysql_string() );
|
|
} elseif ( $value ) {
|
|
$this->set_prop( $column, Clean::string( $value ) );
|
|
} elseif ( null === $value ) {
|
|
$this->set_prop( $column, null );
|
|
}
|
|
}
|
|
}
|