160 lines
3.5 KiB
PHP
160 lines
3.5 KiB
PHP
<?php
|
|
namespace ElementorPro\Core\Database;
|
|
|
|
use ElementorPro\Core\Utils\Collection;
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit; // Exit if accessed directly.
|
|
}
|
|
|
|
abstract class Model_Base implements \JsonSerializable {
|
|
|
|
// Casting types.
|
|
const TYPE_BOOLEAN = 'boolean';
|
|
const TYPE_COLLECTION = 'collection';
|
|
const TYPE_INTEGER = 'integer';
|
|
const TYPE_STRING = 'string';
|
|
const TYPE_JSON = 'json';
|
|
const TYPE_DATETIME = 'datetime';
|
|
const TYPE_DATETIME_GMT = 'datetime_gmt';
|
|
|
|
/**
|
|
* Casts array.
|
|
* Used to automatically cast values from DB to the appropriate property type.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected static $casts = [];
|
|
|
|
/**
|
|
* Model_Base constructor.
|
|
*
|
|
* @param array $fields - Fields from the DB to fill.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function __construct( array $fields ) {
|
|
foreach ( $fields as $key => $value ) {
|
|
if ( ! property_exists( $this, $key ) ) {
|
|
continue;
|
|
}
|
|
|
|
$this->{$key} = ( empty( static::$casts[ $key ] ) )
|
|
? $value
|
|
: static::cast( $value, static::$casts[ $key ] );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the model's table name.
|
|
* Throws an exception by default in order to require implementation,
|
|
* since abstract static functions are not allowed.
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function get_table() {
|
|
throw new \Exception( 'You must implement `get_table()` inside ' . static::class );
|
|
}
|
|
|
|
/**
|
|
* Create a Query Builder for the model's table.
|
|
*
|
|
* @param \wpdb|null $connection - MySQL connection to use.
|
|
*
|
|
* @return Query_Builder
|
|
*/
|
|
public static function query( \wpdb $connection = null ) {
|
|
$builder = new Model_Query_Builder( static::class, $connection );
|
|
|
|
return $builder->from( static::get_table() );
|
|
}
|
|
|
|
/**
|
|
* Cast value into specific type.
|
|
*
|
|
* @param $value - Value to cast.
|
|
* @param $type - Type to cast into.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
protected static function cast( $value, $type ) {
|
|
if ( null === $value ) {
|
|
return null;
|
|
}
|
|
|
|
switch ( $type ) {
|
|
case self::TYPE_BOOLEAN:
|
|
return boolval( $value );
|
|
|
|
case self::TYPE_COLLECTION:
|
|
return new Collection( $value );
|
|
|
|
case self::TYPE_INTEGER:
|
|
return intval( $value );
|
|
|
|
case self::TYPE_STRING:
|
|
return strval( $value );
|
|
|
|
case self::TYPE_JSON:
|
|
return json_decode( $value, true );
|
|
|
|
case self::TYPE_DATETIME:
|
|
return new \DateTime( $value );
|
|
|
|
case self::TYPE_DATETIME_GMT:
|
|
return new \DateTime( $value, new \DateTimeZone( 'GMT' ) );
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* Cast a model property value into a JSON compatible data type.
|
|
*
|
|
* @param $value - Value to cast.
|
|
* @param $type - Type to cast into.
|
|
* @param $property_name - The model property name.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
protected static function json_serialize_property( $value, $type, $property_name ) {
|
|
switch ( $type ) {
|
|
case self::TYPE_DATETIME:
|
|
case self::TYPE_DATETIME_GMT:
|
|
/** @var \DateTime $value */
|
|
return $value->format( 'c' );
|
|
}
|
|
|
|
/** @var mixed $value */
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
#[\ReturnTypeWillChange]
|
|
public function jsonSerialize() {
|
|
return ( new Collection( (array) $this ) )
|
|
->map( function ( $_, $key ) {
|
|
$value = $this->{$key};
|
|
|
|
$type = array_key_exists( $key, static::$casts )
|
|
? static::$casts[ $key ]
|
|
: null;
|
|
|
|
if ( null === $value ) {
|
|
return $value;
|
|
}
|
|
|
|
// Can be overridden by child model.
|
|
$value = static::json_serialize_property( $value, $type, $key );
|
|
|
|
if ( $value instanceof \JsonSerializable ) {
|
|
return $value->jsonSerialize();
|
|
}
|
|
|
|
return $value;
|
|
} )
|
|
->all();
|
|
}
|
|
}
|