| 1 |
<?php |
| 2 |
|
| 3 |
#[AllowDynamicProperties] |
| 4 |
class OsModel { |
| 5 |
|
| 6 |
protected $error, |
| 7 |
$db; |
| 8 |
|
| 9 |
public $nice_names = []; |
| 10 |
protected $comparisons = array( '>=', '<=', '<', '>', '!=', 'LIKE' ); |
| 11 |
protected $conditions = []; |
| 12 |
protected $limit = false; |
| 13 |
protected $offset = false; |
| 14 |
protected $select_args = []; |
| 15 |
protected $order_args = false; |
| 16 |
protected $group_args = false; |
| 17 |
protected $having_args = false; |
| 18 |
protected $joins = []; |
| 19 |
public $data_vars = []; |
| 20 |
public $first_level_data_vars = []; |
| 21 |
public $form_id = false; |
| 22 |
public $last_query = ''; |
| 23 |
protected $meta_class = false; |
| 24 |
public $meta = false; |
| 25 |
public $table_name = ''; |
| 26 |
public $join_attributes = []; |
| 27 |
|
| 28 |
function __construct( $id = false ) { |
| 29 |
$this->error = false; |
| 30 |
global $wpdb; |
| 31 |
$this->db = $wpdb; |
| 32 |
if ( $id ) { |
| 33 |
$this->load_by_id( $id ); |
| 34 |
} |
| 35 |
} |
| 36 |
|
| 37 |
public function __get( $property ) { |
| 38 |
$method = "get_$property"; |
| 39 |
if ( method_exists( $this, $method ) ) { |
| 40 |
return $this->$method(); |
| 41 |
} |
| 42 |
} |
| 43 |
|
| 44 |
public function exists() { |
| 45 |
return ( isset( $this->id ) && ! empty( $this->id ) ); |
| 46 |
} |
| 47 |
|
| 48 |
public function formatted_created_date( $format = false, $default = 'n/a' ) { |
| 49 |
if ( ! $format ) { |
| 50 |
$format = OsSettingsHelper::get_readable_date_format(); |
| 51 |
} |
| 52 |
if ( property_exists( $this, 'created_at' ) && isset( $this->created_at ) && ! empty( $this->created_at ) ) { |
| 53 |
$date = new OsWpDateTime( $this->created_at, new DateTimeZone( 'UTC' ) ); |
| 54 |
|
| 55 |
return $date->format( $format ); |
| 56 |
} else { |
| 57 |
return $default; |
| 58 |
} |
| 59 |
} |
| 60 |
public function readable_created_date(): string { |
| 61 |
try { |
| 62 |
return OsTimeHelper::get_readable_date( new OsWpDateTime( $this->created_at, new DateTimeZone( 'UTC' ) ) ); |
| 63 |
} catch ( Exception $e ) { |
| 64 |
return 'n/a'; |
| 65 |
} |
| 66 |
} |
| 67 |
|
| 68 |
public function prepare( $query, $values ) { |
| 69 |
if ( empty( $values ) ) { |
| 70 |
return $query; |
| 71 |
} else { |
| 72 |
return $this->db->prepare( $query, $values ); |
| 73 |
} |
| 74 |
} |
| 75 |
|
| 76 |
|
| 77 |
/** |
| 78 |
* |
| 79 |
* Clears all GROUP BY arguments |
| 80 |
* |
| 81 |
* @return $this OsModel |
| 82 |
*/ |
| 83 |
public function clear_group_by(): OsModel { |
| 84 |
$this->group_args = ''; |
| 85 |
|
| 86 |
return $this; |
| 87 |
} |
| 88 |
|
| 89 |
public function group_by( $group_args ) { |
| 90 |
if ( $this->group_args ) { |
| 91 |
$this->group_args = implode( ',', array( $this->group_args, $group_args ) ); |
| 92 |
} else { |
| 93 |
$this->group_args = $group_args; |
| 94 |
} |
| 95 |
|
| 96 |
return $this; |
| 97 |
} |
| 98 |
|
| 99 |
public function get_group_args() { |
| 100 |
if ( $this->group_args ) { |
| 101 |
return 'GROUP BY ' . $this->group_args; |
| 102 |
} else { |
| 103 |
return ''; |
| 104 |
} |
| 105 |
} |
| 106 |
|
| 107 |
public function clear_having(): OsModel { |
| 108 |
$this->having_args = ''; |
| 109 |
|
| 110 |
return $this; |
| 111 |
} |
| 112 |
|
| 113 |
|
| 114 |
public function get_having_args(): string { |
| 115 |
if ( $this->having_args ) { |
| 116 |
return 'HAVING ' . $this->having_args; |
| 117 |
} |
| 118 |
return ''; |
| 119 |
} |
| 120 |
|
| 121 |
public function having( $having_args ) { |
| 122 |
if ( $this->having_args ) { |
| 123 |
$this->having_args = implode( ',', array( $this->having_args, $having_args ) ); |
| 124 |
} else { |
| 125 |
$this->having_args = $having_args; |
| 126 |
} |
| 127 |
|
| 128 |
return $this; |
| 129 |
} |
| 130 |
|
| 131 |
public function order_by( $order_args ) { |
| 132 |
if ( $this->order_args ) { |
| 133 |
$this->order_args = implode( ',', array( $this->order_args, $order_args ) ); |
| 134 |
} else { |
| 135 |
$this->order_args = $order_args; |
| 136 |
} |
| 137 |
|
| 138 |
return $this; |
| 139 |
} |
| 140 |
|
| 141 |
public function get_order_args() { |
| 142 |
if ( $this->order_args ) { |
| 143 |
return 'ORDER BY ' . $this->order_args; |
| 144 |
} else { |
| 145 |
return ''; |
| 146 |
} |
| 147 |
} |
| 148 |
|
| 149 |
public static function where_in_array_to_string( $array_of_values ) { |
| 150 |
$clean_string = ''; |
| 151 |
if ( is_array( $array_of_values ) ) { |
| 152 |
$array_of_values = array_map( |
| 153 |
function ( $v ) { |
| 154 |
return "'" . esc_sql( $v ) . "'"; |
| 155 |
}, |
| 156 |
$array_of_values |
| 157 |
); |
| 158 |
$clean_string = ' (' . implode( ',', $array_of_values ) . ') '; |
| 159 |
} |
| 160 |
|
| 161 |
return $clean_string; |
| 162 |
} |
| 163 |
|
| 164 |
|
| 165 |
/** |
| 166 |
* @param array $conditions |
| 167 |
* |
| 168 |
* @return $this |
| 169 |
*/ |
| 170 |
public function filter_where_conditions( array $allowed_conditions ): OsModel { |
| 171 |
foreach ( $allowed_conditions as $condition_name => $allowed_condition_value ) { |
| 172 |
if ( empty( $this->conditions[ $condition_name ] ) ) { |
| 173 |
$this->conditions[ $condition_name ] = $allowed_condition_value; |
| 174 |
} else { |
| 175 |
// convert both to arrays to compare |
| 176 |
$current_value = is_array( $this->conditions[ $condition_name ] ) ? $this->conditions[ $condition_name ] : OsUtilHelper::explode_and_trim( $this->conditions[ $condition_name ] ); |
| 177 |
$allowed_value = is_array( $allowed_condition_value ) ? $allowed_condition_value : OsUtilHelper::explode_and_trim( $allowed_condition_value ); |
| 178 |
$this->conditions[ $condition_name ] = array_intersect( $current_value, $allowed_value ); |
| 179 |
} |
| 180 |
} |
| 181 |
|
| 182 |
return $this; |
| 183 |
} |
| 184 |
|
| 185 |
public function where( $conditions ) { |
| 186 |
if ( empty( $conditions ) ) { |
| 187 |
return $this; |
| 188 |
} |
| 189 |
$this->conditions = array_merge( $this->conditions, $conditions ); |
| 190 |
|
| 191 |
return $this; |
| 192 |
} |
| 193 |
|
| 194 |
public function where_in( $column, $array_of_values ) { |
| 195 |
$condition = array( "{$column} IN " => $array_of_values ); |
| 196 |
$this->conditions = array_merge( $this->conditions, $condition ); |
| 197 |
|
| 198 |
return $this; |
| 199 |
} |
| 200 |
|
| 201 |
public function where_not_in( $column, $array_of_values ) { |
| 202 |
$condition = array( "{$column} NOT IN " => $array_of_values ); |
| 203 |
$this->conditions = array_merge( $this->conditions, $condition ); |
| 204 |
|
| 205 |
return $this; |
| 206 |
} |
| 207 |
|
| 208 |
public function join( $table, $on_args, $type = '' ) { |
| 209 |
$this->joins[] = [ |
| 210 |
'join_table' => $table, |
| 211 |
'join_on_args' => $on_args, |
| 212 |
'join_type' => in_array( $type, [ 'left', 'right' ] ) ? $type : '', |
| 213 |
]; |
| 214 |
|
| 215 |
return $this; |
| 216 |
} |
| 217 |
|
| 218 |
public function get_join_string(): string { |
| 219 |
$join_query = ''; |
| 220 |
if ( ! empty( $this->joins ) ) { |
| 221 |
foreach ( $this->joins as $join_data ) { |
| 222 |
if ( empty( $join_data['join_table'] ) || empty( $join_data['join_on_args'] ) ) { |
| 223 |
continue; |
| 224 |
} |
| 225 |
$join_query .= $join_data['join_type'] . ' JOIN ' . $join_data['join_table'] . ' ON ' . $this->build_join_args_query( $join_data['join_table'], $join_data['join_on_args'] ); |
| 226 |
} |
| 227 |
} |
| 228 |
|
| 229 |
return $join_query; |
| 230 |
} |
| 231 |
|
| 232 |
private function build_join_args_query( $join_table, $join_on_args ) { |
| 233 |
$join_args_query_arr = []; |
| 234 |
foreach ( $join_on_args as $column_one => $column_two ) { |
| 235 |
if ( is_array( $column_two ) ) { |
| 236 |
$in_values = implode( ',', $column_two ); |
| 237 |
$join_args_query_arr[] = "{$join_table}.{$column_one} IN ({$in_values})"; |
| 238 |
} else { |
| 239 |
$join_args_query_arr[] = "{$join_table}.{$column_one} = {$column_two}"; |
| 240 |
} |
| 241 |
} |
| 242 |
|
| 243 |
return implode( ' AND ', $join_args_query_arr ); |
| 244 |
} |
| 245 |
|
| 246 |
|
| 247 |
/** |
| 248 |
* |
| 249 |
* Clears all SELECT arguments |
| 250 |
* |
| 251 |
* @return $this OsModel |
| 252 |
*/ |
| 253 |
public function clear_select(): OsModel { |
| 254 |
$this->select_args = []; |
| 255 |
|
| 256 |
return $this; |
| 257 |
} |
| 258 |
|
| 259 |
/** |
| 260 |
* |
| 261 |
* Adds arguments to SELECT query |
| 262 |
* |
| 263 |
* @param $select_args Array|string or comma separated String of arguments |
| 264 |
* |
| 265 |
* @return $this OsModel |
| 266 |
*/ |
| 267 |
public function select( $select_args ): OsModel { |
| 268 |
if ( ! is_array( $select_args ) ) { |
| 269 |
$select_args = OsUtilHelper::explode_and_trim( $select_args ); |
| 270 |
} |
| 271 |
if ( ! empty( $select_args ) ) { |
| 272 |
$this->select_args = array_merge( $this->select_args, $select_args ); |
| 273 |
} |
| 274 |
|
| 275 |
return $this; |
| 276 |
} |
| 277 |
|
| 278 |
public function build_select_args_string(): string { |
| 279 |
$select_args = $this->get_select_args(); |
| 280 |
if ( empty( $select_args ) ) { |
| 281 |
return '*'; |
| 282 |
} else { |
| 283 |
return implode( ',', array_unique( $this->select_args ) ); |
| 284 |
} |
| 285 |
} |
| 286 |
|
| 287 |
public function get_select_args(): array { |
| 288 |
return $this->select_args; |
| 289 |
} |
| 290 |
|
| 291 |
/** |
| 292 |
* Eager load meta key-value pairs associated with this model |
| 293 |
* |
| 294 |
* @param array $meta_keys |
| 295 |
* |
| 296 |
* @return $this |
| 297 |
*/ |
| 298 |
public function with_meta( array $meta_keys = [] ): OsModel { |
| 299 |
$this->meta = []; |
| 300 |
$meta_class = $this->meta_class; |
| 301 |
|
| 302 |
if ( $this->exists() && $meta_class && class_exists( $meta_class ) ) { |
| 303 |
/** @var OsMetaModel $meta_object */ |
| 304 |
$meta_object = new $meta_class(); |
| 305 |
if ( ! empty( $meta_keys ) ) { |
| 306 |
foreach ( $meta_keys as $meta_key ) { |
| 307 |
$this->meta[] = [ $meta_key => $meta_object->get_by_key( $meta_key, $this->id ) ]; |
| 308 |
} |
| 309 |
} else { |
| 310 |
$this->meta = $meta_object->get_by_object_id( $this->id ); |
| 311 |
} |
| 312 |
} |
| 313 |
|
| 314 |
return $this; |
| 315 |
} |
| 316 |
|
| 317 |
public function set_limit( $limit ) { |
| 318 |
$this->limit = $limit; |
| 319 |
|
| 320 |
return $this; |
| 321 |
} |
| 322 |
|
| 323 |
public function count() { |
| 324 |
$count = $this->clear_select()->clear_group_by()->clear_having()->select( 'COUNT(DISTINCT(' . $this->table_name . '.id)) as total' )->set_limit( 1 )->get_results(); |
| 325 |
$total = ( $count ) ? $count->total : 0; |
| 326 |
|
| 327 |
return $total; |
| 328 |
} |
| 329 |
|
| 330 |
|
| 331 |
public function set_offset( $offset ) { |
| 332 |
$this->offset = $offset; |
| 333 |
|
| 334 |
return $this; |
| 335 |
} |
| 336 |
|
| 337 |
protected function with_table_name( $column ) { |
| 338 |
if ( ! is_numeric( $column ) && ! in_array( |
| 339 |
$column, |
| 340 |
[ |
| 341 |
'AND', |
| 342 |
'OR', |
| 343 |
] |
| 344 |
) && ( strpos( $column, '(' ) === false ) && ( strpos( $column, '.' ) === false ) ) { |
| 345 |
return $this->table_name . '.' . $column; |
| 346 |
} else { |
| 347 |
return $column; |
| 348 |
} |
| 349 |
} |
| 350 |
|
| 351 |
protected function build_conditions_query( $conditions, $logical_operator = 'AND' ) { |
| 352 |
$where_conditions = []; |
| 353 |
$where_values = []; |
| 354 |
$sql_query = ''; |
| 355 |
$index = 0; |
| 356 |
if ( $conditions ) { |
| 357 |
foreach ( $conditions as $column => $value ) { |
| 358 |
$temp_query = false; |
| 359 |
if ( $column == 'OR' || $column == 'AND' ) { |
| 360 |
$sql_query .= '('; |
| 361 |
$conditions_and_values = $this->build_conditions_query( $value, $column ); |
| 362 |
$sql_query .= $conditions_and_values[0]; |
| 363 |
$where_values = array_merge( $where_values, $conditions_and_values[1] ); |
| 364 |
$sql_query .= ')'; |
| 365 |
} else { |
| 366 |
// Check if its a comparison condition e.g. <, >, <=, >= etc... |
| 367 |
foreach ( $this->comparisons as $comparison ) { |
| 368 |
if ( strpos( $column, $comparison ) ) { |
| 369 |
$column = str_replace( $comparison, '', $column ); |
| 370 |
$temp_query = $this->with_table_name( $column ) . $comparison . ' %s'; |
| 371 |
} |
| 372 |
} |
| 373 |
// WHERE IN query |
| 374 |
if ( strpos( $column, ' NOT IN' ) && is_array( $value ) ) { |
| 375 |
$temp_query = $this->with_table_name( $column ) . OsModel::where_in_array_to_string( $value ); |
| 376 |
|
| 377 |
} elseif ( strpos( $column, ' IN' ) && is_array( $value ) ) { |
| 378 |
$temp_query = $this->with_table_name( $column ) . OsModel::where_in_array_to_string( $value ); |
| 379 |
} elseif ( is_array( $value ) && ( isset( $value['OR'] ) || isset( $value['AND'] ) ) ) { |
| 380 |
// IS ARRAY AND OR |
| 381 |
foreach ( $value as $condition_and_or => $condition_values ) { |
| 382 |
|
| 383 |
$temp_query .= '('; |
| 384 |
$sub_queries = []; |
| 385 |
foreach ( $condition_values as $condition_key => $condition_value ) { |
| 386 |
if ( is_string( $condition_key ) && is_string( $column ) ) { |
| 387 |
// Only allow whitelisted comparison operators as condition suffix keys. |
| 388 |
// Arbitrary string keys would be concatenated directly into SQL — reject them. |
| 389 |
if ( ! in_array( trim( $condition_key ), $this->comparisons, true ) ) { |
| 390 |
continue; |
| 391 |
} |
| 392 |
$temp_key = $this->with_table_name( $column ) . $condition_key; |
| 393 |
$sub_conditions = [ $temp_key => $condition_value ]; |
| 394 |
} elseif ( is_string( $condition_key ) ) { |
| 395 |
$sub_conditions = [ $this->with_table_name( $condition_key ) => $condition_value ]; |
| 396 |
} else { |
| 397 |
$sub_conditions = [ $column => $condition_value ]; |
| 398 |
} |
| 399 |
$conditions_and_values = $this->build_conditions_query( $sub_conditions, $condition_and_or ); |
| 400 |
$sub_queries[] = $conditions_and_values[0]; |
| 401 |
$where_values = array_merge( $where_values, $conditions_and_values[1] ); |
| 402 |
} |
| 403 |
$temp_query .= implode( ' ' . $condition_and_or . ' ', $sub_queries ); |
| 404 |
$temp_query .= ')'; |
| 405 |
} |
| 406 |
} elseif ( $value === 'IS NULL' ) { |
| 407 |
// IS NULL |
| 408 |
$temp_query = $this->with_table_name( $column ) . ' IS NULL '; |
| 409 |
} elseif ( $value === 'IS NOT NULL' ) { |
| 410 |
// IS NOT NULL |
| 411 |
$temp_query = $this->with_table_name( $column ) . ' IS NOT NULL '; |
| 412 |
} elseif ( is_array( $value ) && ! empty( $value ) ) { |
| 413 |
$temp_query = $this->with_table_name( $column ) . ' IN ' . OsModel::where_in_array_to_string( $value ); |
| 414 |
} else { |
| 415 |
// Add to list of query values |
| 416 |
if ( is_array( $value ) ) { |
| 417 |
$where_values[] = OsModel::where_in_array_to_string( $value ); |
| 418 |
} else { |
| 419 |
$where_values[] = $value; |
| 420 |
} |
| 421 |
} |
| 422 |
if ( $temp_query ) { |
| 423 |
$sql_query .= $temp_query; |
| 424 |
} else { |
| 425 |
$sql_query .= $this->with_table_name( $column ) . '= %s'; |
| 426 |
} |
| 427 |
} |
| 428 |
$index++; |
| 429 |
if ( $index < count( $conditions ) ) { |
| 430 |
$sql_query .= ' ' . $logical_operator . ' '; |
| 431 |
} |
| 432 |
} |
| 433 |
} |
| 434 |
|
| 435 |
return array( $sql_query, $where_values ); |
| 436 |
} |
| 437 |
|
| 438 |
|
| 439 |
public function escape_by_ref( &$string ) { |
| 440 |
$this->db->escape_by_ref( $string ); |
| 441 |
} |
| 442 |
|
| 443 |
public function get_results( $results_type = OBJECT ) { |
| 444 |
$conditions_and_values = $this->build_conditions_query( $this->conditions ); |
| 445 |
if ( $conditions_and_values[0] ) { |
| 446 |
$where_query = 'WHERE ' . $conditions_and_values[0]; |
| 447 |
} else { |
| 448 |
$where_query = ''; |
| 449 |
} |
| 450 |
if ( $this->limit ) { |
| 451 |
$limit_query = ' LIMIT %d'; |
| 452 |
$conditions_and_values[1][] = $this->limit; |
| 453 |
} else { |
| 454 |
$limit_query = ''; |
| 455 |
} |
| 456 |
|
| 457 |
|
| 458 |
if ( $this->offset ) { |
| 459 |
$offset_query = ' OFFSET %d'; |
| 460 |
$conditions_and_values[1][] = $this->offset; |
| 461 |
} else { |
| 462 |
$offset_query = ''; |
| 463 |
} |
| 464 |
|
| 465 |
$query = 'SELECT ' . $this->build_select_args_string() . ' FROM ' . $this->table_name . ' ' . $this->get_join_string() . ' ' . $where_query . ' ' . $this->get_group_args() . ' ' . $this->get_having_args() . ' ' . $this->get_order_args() . ' ' . $limit_query . ' ' . $offset_query; |
| 466 |
|
| 467 |
$this->last_query = vsprintf( $query, $conditions_and_values[1] ); |
| 468 |
OsDebugHelper::log_query( $this->last_query ); |
| 469 |
|
| 470 |
$items = $this->db->get_results( |
| 471 |
$this->prepare( $query, $conditions_and_values[1] ), |
| 472 |
$results_type |
| 473 |
); |
| 474 |
|
| 475 |
if ( ( $this->limit == 1 ) && isset( $items[0] ) ) { |
| 476 |
$items = $items[0]; |
| 477 |
} |
| 478 |
|
| 479 |
return $items; |
| 480 |
} |
| 481 |
|
| 482 |
|
| 483 |
public function get_query_results( $query, $values = [], $results_type = OBJECT ) { |
| 484 |
$this->last_query = $query; |
| 485 |
$items = $this->db->get_results( |
| 486 |
$this->prepare( $query, $values ), |
| 487 |
$results_type |
| 488 |
); |
| 489 |
OsDebugHelper::log_query( $query ); |
| 490 |
|
| 491 |
return $items; |
| 492 |
} |
| 493 |
|
| 494 |
|
| 495 |
public function reset_conditions() { |
| 496 |
$this->conditions = []; |
| 497 |
} |
| 498 |
|
| 499 |
|
| 500 |
/** |
| 501 |
* @param $query |
| 502 |
* @param $values |
| 503 |
* |
| 504 |
* @return static|static[] |
| 505 |
*/ |
| 506 |
public function get_results_as_models( $query = false, $values = [] ) { |
| 507 |
if ( $query ) { |
| 508 |
$items = $this->get_query_results( $query, $values ); |
| 509 |
} else { |
| 510 |
$items = $this->get_results(); |
| 511 |
} |
| 512 |
$models = []; |
| 513 |
if ( empty( $items ) ) { |
| 514 |
return []; |
| 515 |
} |
| 516 |
if ( $this->limit == 1 ) { |
| 517 |
$items = [ $items ]; |
| 518 |
} |
| 519 |
foreach ( $items as $item ) { |
| 520 |
$current_class_name = get_class( $this ); |
| 521 |
$model = new $current_class_name(); |
| 522 |
foreach ( $item as $prop_name => $prop_value ) { |
| 523 |
$model->$prop_name = $prop_value; |
| 524 |
} |
| 525 |
/** |
| 526 |
* A child of <code>OsModel</code> is about to be added to the result set |
| 527 |
* |
| 528 |
* @param {OsModel} $model Instance of model that should be filtered |
| 529 |
* @returns {OsModel} Instance of model that has been filtered |
| 530 |
* |
| 531 |
* @since 1.0.0 |
| 532 |
* @hook latepoint_get_results_as_models |
| 533 |
* |
| 534 |
*/ |
| 535 |
$model = apply_filters( 'latepoint_get_results_as_models', $model ); |
| 536 |
if ( $model ) { |
| 537 |
$models[] = $model; |
| 538 |
} |
| 539 |
} |
| 540 |
$this->reset_conditions(); |
| 541 |
if ( $this->limit == 1 && isset( $models[0] ) ) { |
| 542 |
$models = $models[0]; |
| 543 |
} |
| 544 |
|
| 545 |
return $models; |
| 546 |
} |
| 547 |
|
| 548 |
public function filter_allowed_records(): OsModel { |
| 549 |
return $this; |
| 550 |
} |
| 551 |
|
| 552 |
public function get_image_url( $size = 'thumbnail' ) { |
| 553 |
$url = OsImageHelper::get_image_url_by_id( $this->image_id, $size ); |
| 554 |
|
| 555 |
return $url; |
| 556 |
} |
| 557 |
|
| 558 |
public function set_data( $data, $role = 'admin', $sanitize = true ) { |
| 559 |
$data = $this->prepare_data_before_it_is_set( $data ); |
| 560 |
/** |
| 561 |
* Data/Params are being prepared to be set on a child of <code>OsModel</code> |
| 562 |
* |
| 563 |
* @param {OsModel} $this Instance of model that data is to be set on |
| 564 |
* @param {array} $data Array of data/params to be set |
| 565 |
* |
| 566 |
* @since 1.0.0 |
| 567 |
* @hook latepoint_model_prepare_set_data |
| 568 |
* |
| 569 |
*/ |
| 570 |
do_action( 'latepoint_model_prepare_set_data', $this, $data ); |
| 571 |
if ( is_array( $data ) ) { |
| 572 |
// array passed |
| 573 |
// if ID is passed and model not loaded from db yet - load data from db |
| 574 |
if ( isset( $data['id'] ) && is_numeric( $data['id'] ) && property_exists( $this, 'id' ) && $this->is_new_record() ) { |
| 575 |
$this->load_by_id( $data['id'] ); |
| 576 |
} |
| 577 |
foreach ( $this->get_allowed_params( $role ) as $param ) { |
| 578 |
if ( isset( $data[ $param ] ) ) { |
| 579 |
$this->$param = $sanitize ? $this->sanitize_param( $param, $data[ $param ] ) : $data[ $param ]; |
| 580 |
} |
| 581 |
} |
| 582 |
} else { |
| 583 |
// object passed |
| 584 |
// if ID is passed and model not loaded from db yet - load data from db |
| 585 |
if ( isset( $data->id ) && is_numeric( $data->id ) && property_exists( $this, 'id' ) && $this->is_new_record() ) { |
| 586 |
$this->load_by_id( $data->id ); |
| 587 |
} |
| 588 |
foreach ( $this->get_allowed_params( $role ) as $param ) { |
| 589 |
if ( isset( $data->$param ) ) { |
| 590 |
$this->$param = $sanitize ? $this->sanitize_param( $param, $data->$param ) : $data->$param; |
| 591 |
} |
| 592 |
} |
| 593 |
} |
| 594 |
/** |
| 595 |
* Data/Params have been set on a child of <code>OsModel</code> |
| 596 |
* |
| 597 |
* @param {OsModel} $this Instance of model that data was set on |
| 598 |
* @param {array} $data Array of data/params that was set |
| 599 |
* |
| 600 |
* @since 1.0.0 |
| 601 |
* @hook latepoint_model_set_data |
| 602 |
* |
| 603 |
*/ |
| 604 |
do_action( 'latepoint_model_set_data', $this, $data ); |
| 605 |
$this->after_data_was_set( $data ); |
| 606 |
|
| 607 |
return $this; |
| 608 |
} |
| 609 |
|
| 610 |
/** |
| 611 |
* @return void |
| 612 |
* |
| 613 |
* Useful for child classes, to do something after a data is set |
| 614 |
*/ |
| 615 |
public function after_data_was_set( $data ) { |
| 616 |
} |
| 617 |
|
| 618 |
|
| 619 |
/** |
| 620 |
* @return void |
| 621 |
* |
| 622 |
* Useful for child classes, to do something after a data is set |
| 623 |
*/ |
| 624 |
public function prepare_data_before_it_is_set( $data ) { |
| 625 |
return $data; |
| 626 |
} |
| 627 |
|
| 628 |
|
| 629 |
public function delete_where( $where = false, $where_format = null ) { |
| 630 |
if ( is_array( $where ) && $this->db->delete( $this->table_name, $where, $where_format ) ) { |
| 631 |
return true; |
| 632 |
} else { |
| 633 |
return false; |
| 634 |
} |
| 635 |
} |
| 636 |
|
| 637 |
public function delete( $id = false ) { |
| 638 |
if ( ! $id && isset( $this->id ) ) { |
| 639 |
$id = $this->id; |
| 640 |
} |
| 641 |
if ( $id && $this->db->delete( $this->table_name, array( 'id' => $id ), array( '%d' ) ) ) { |
| 642 |
/** |
| 643 |
* A child of <code>OsModel</code> has been deleted |
| 644 |
* |
| 645 |
* @param {OsModel} $this Instance of model that has been deleted |
| 646 |
* @param {integer} $id ID of model instance that has been deleted |
| 647 |
* |
| 648 |
* @since 4.6.3 |
| 649 |
* @hook latepoint_model_deleted |
| 650 |
* |
| 651 |
*/ |
| 652 |
do_action( 'latepoint_model_deleted', $this, $id ); |
| 653 |
|
| 654 |
return true; |
| 655 |
} else { |
| 656 |
return false; |
| 657 |
} |
| 658 |
} |
| 659 |
|
| 660 |
|
| 661 |
public function load_from_row_data( $row_data ) { |
| 662 |
foreach ( $row_data as $key => $field ) { |
| 663 |
if ( property_exists( $this, $key ) ) { |
| 664 |
$this->$key = $field; |
| 665 |
} |
| 666 |
} |
| 667 |
} |
| 668 |
|
| 669 |
public function load_by_id( $id ) { |
| 670 |
if ( filter_var( $id, FILTER_VALIDATE_INT ) === false ) { |
| 671 |
return false; |
| 672 |
} |
| 673 |
$query = $this->prepare( 'SELECT ' . $this->build_select_args_string() . ' FROM ' . $this->table_name . ' WHERE id = %d', $id ); |
| 674 |
$result_row = $this->db->get_row( $query, ARRAY_A ); |
| 675 |
|
| 676 |
if ( $result_row ) { |
| 677 |
foreach ( $result_row as $row_key => $row_value ) { |
| 678 |
if ( property_exists( $this, $row_key ) ) { |
| 679 |
$this->$row_key = $row_value; |
| 680 |
} |
| 681 |
} |
| 682 |
|
| 683 |
/** |
| 684 |
* A child of <code>OsModel</code> has been loaded from the DB by its ID |
| 685 |
* |
| 686 |
* @param {OsModel} $this Instance of model that has been loaded |
| 687 |
* @returns {OsModel} Instance of model that has been filtered |
| 688 |
* |
| 689 |
* @since 1.0.0 |
| 690 |
* @hook latepoint_model_loaded_by_id |
| 691 |
* |
| 692 |
*/ |
| 693 |
return apply_filters( 'latepoint_model_loaded_by_id', $this ); |
| 694 |
} else { |
| 695 |
return false; |
| 696 |
} |
| 697 |
} |
| 698 |
|
| 699 |
|
| 700 |
/** |
| 701 |
* |
| 702 |
* Generates an ID that is used in a form for quick editing. Returns ID if exists or returns a "new_HASH" to be used |
| 703 |
* as ID to indicate that it's a new record |
| 704 |
* |
| 705 |
* @return string |
| 706 |
*/ |
| 707 |
public function get_form_id(): string { |
| 708 |
if ( $this->is_new_record() ) { |
| 709 |
if ( empty( $this->form_id ) ) { |
| 710 |
$this->form_id = OsUtilHelper::generate_form_id(); |
| 711 |
} |
| 712 |
} else { |
| 713 |
$this->form_id = $this->id; |
| 714 |
} |
| 715 |
|
| 716 |
return $this->form_id; |
| 717 |
} |
| 718 |
|
| 719 |
|
| 720 |
public function is_new_record() { |
| 721 |
if ( $this->id ) { |
| 722 |
return false; |
| 723 |
} else { |
| 724 |
return true; |
| 725 |
} |
| 726 |
} |
| 727 |
|
| 728 |
public function get_field( $field_name ) { |
| 729 |
return $this->$field_name; |
| 730 |
} |
| 731 |
|
| 732 |
public function set_field( $field_name, $field_value ) { |
| 733 |
$this->$field_name = $field_value; |
| 734 |
} |
| 735 |
|
| 736 |
protected function before_save() { |
| 737 |
} |
| 738 |
|
| 739 |
protected function before_create() { |
| 740 |
} |
| 741 |
|
| 742 |
// updates array of attributes |
| 743 |
public function update_attributes( $data, $sanitize = true ) { |
| 744 |
if ( $this->is_new_record() ) { |
| 745 |
return false; |
| 746 |
} |
| 747 |
$prepared_data = []; |
| 748 |
foreach ( $data as $key => $value ) { |
| 749 |
if ( property_exists( $this, $key ) ) { |
| 750 |
if ( $sanitize && array_key_exists( $key, $this->params_to_sanitize() ) ) { |
| 751 |
$value = OsParamsHelper::sanitize_param( $value, $this->params_to_sanitize()[ $key ] ); |
| 752 |
} |
| 753 |
$this->$key = $value; |
| 754 |
// encrypt value if it needs to be encrypted, however the model object itself stores an un-encrypted value |
| 755 |
if ( in_array( $key, $this->encrypted_params() ) ) { |
| 756 |
$value = OsEncryptHelper::encrypt_value(); |
| 757 |
} |
| 758 |
$prepared_data[ $key ] = $value; |
| 759 |
} |
| 760 |
} |
| 761 |
if ( empty( $prepared_data ) ) { |
| 762 |
return false; |
| 763 |
} else { |
| 764 |
$now = OsTimeHelper::now_datetime_in_format( LATEPOINT_DATETIME_DB_FORMAT ); |
| 765 |
if ( property_exists( $this, 'updated_at' ) ) { |
| 766 |
$prepared_data['updated_at'] = $now; |
| 767 |
} |
| 768 |
if ( false === $this->db->update( $this->table_name, $prepared_data, array( 'id' => $this->id ) ) ) { |
| 769 |
$this->add_error( 'update_error', $this->db->last_error ); |
| 770 |
|
| 771 |
return false; |
| 772 |
} else { |
| 773 |
if ( property_exists( $this, 'updated_at' ) ) { |
| 774 |
$this->updated_at = $now; |
| 775 |
} |
| 776 |
OsDebugHelper::log_query( $this->db->last_query ); |
| 777 |
|
| 778 |
return true; |
| 779 |
} |
| 780 |
} |
| 781 |
} |
| 782 |
|
| 783 |
protected function set_defaults() { |
| 784 |
} |
| 785 |
|
| 786 |
// searches list of params that need to be sanitised and returns sanitised value |
| 787 |
protected function sanitize_param( $param_name, $value ) { |
| 788 |
if ( $this->params_to_sanitize() && is_array( $this->params_to_sanitize() ) && array_key_exists( $param_name, $this->params_to_sanitize() ) ) { |
| 789 |
$value = OsParamsHelper::sanitize_param( $value, $this->params_to_sanitize()[ $param_name ] ); |
| 790 |
} |
| 791 |
|
| 792 |
return $value; |
| 793 |
} |
| 794 |
|
| 795 |
public function prepare_and_validate( $alternative_validation = false, $skip_properties = [] ): bool { |
| 796 |
try { |
| 797 |
$this->set_defaults(); |
| 798 |
$this->before_save(); |
| 799 |
if ( $this->validate( $alternative_validation, $skip_properties ) ) { |
| 800 |
return true; |
| 801 |
} else { |
| 802 |
return false; |
| 803 |
} |
| 804 |
} catch ( Exception $e ) { |
| 805 |
$this->add_error( 'validate_exception', $e->getMessage() ); |
| 806 |
|
| 807 |
return false; |
| 808 |
} |
| 809 |
} |
| 810 |
|
| 811 |
public function save( $alternative_validation = false, $skip_validation = false ) { |
| 812 |
try { |
| 813 |
$this->set_defaults(); |
| 814 |
$this->before_save(); |
| 815 |
if ( $skip_validation || $this->validate( $alternative_validation ) ) { |
| 816 |
if ( property_exists( $this, 'updated_at' ) ) { |
| 817 |
$this->updated_at = OsTimeHelper::now_datetime_in_format( LATEPOINT_DATETIME_DB_FORMAT ); |
| 818 |
} |
| 819 |
if ( $this->is_new_record() ) { |
| 820 |
// New Record (insert) |
| 821 |
$this->before_create(); |
| 822 |
if ( property_exists( $this, 'created_at' ) ) { |
| 823 |
$this->created_at = OsTimeHelper::now_datetime_in_format( LATEPOINT_DATETIME_DB_FORMAT ); |
| 824 |
} |
| 825 |
if ( false === $this->db->insert( $this->table_name, $this->get_params_to_save_with_values() ) && property_exists( $this, 'id' ) ) { |
| 826 |
$this->add_error( 'insert_error', $this->db->last_error ); |
| 827 |
|
| 828 |
return false; |
| 829 |
} else { |
| 830 |
OsDebugHelper::log_query( $this->db->last_query ); |
| 831 |
$this->id = $this->db->insert_id; |
| 832 |
} |
| 833 |
} else { |
| 834 |
// Existing record (update) |
| 835 |
if ( false === $this->db->update( $this->table_name, $this->get_params_to_save_with_values(), array( 'id' => $this->id ) ) ) { |
| 836 |
$this->add_error( 'update_error', $this->db->last_error ); |
| 837 |
|
| 838 |
return false; |
| 839 |
} else { |
| 840 |
OsDebugHelper::log_query( $this->db->last_query ); |
| 841 |
} |
| 842 |
} |
| 843 |
/** |
| 844 |
* A child of <code>OsModel</code> has been saved to the DB |
| 845 |
* |
| 846 |
* @param {OsModel} $this Instance of model that has been saved |
| 847 |
* |
| 848 |
* @since 1.0.0 |
| 849 |
* @hook latepoint_model_save |
| 850 |
* |
| 851 |
*/ |
| 852 |
do_action( 'latepoint_model_save', $this ); |
| 853 |
} else { |
| 854 |
return false; |
| 855 |
} |
| 856 |
|
| 857 |
return true; |
| 858 |
} catch ( Exception $e ) { |
| 859 |
$this->add_error( 'save_exception', $e->getMessage() ); |
| 860 |
|
| 861 |
return false; |
| 862 |
} |
| 863 |
} |
| 864 |
|
| 865 |
|
| 866 |
protected function get_property_nice_name( $property ) { |
| 867 |
if ( isset( $this->nice_names[ $property ] ) ) { |
| 868 |
return $this->nice_names[ $property ]; |
| 869 |
} else { |
| 870 |
return ucwords( str_replace( '_', ' ', $property ) ); |
| 871 |
} |
| 872 |
} |
| 873 |
|
| 874 |
protected function get_params_to_save_with_values( $role = 'admin' ) { |
| 875 |
$params_to_save = $this->get_params_to_save( $role ); |
| 876 |
$params_to_save_with_values = []; |
| 877 |
|
| 878 |
foreach ( $params_to_save as $param_name ) { |
| 879 |
if ( property_exists( $this, $param_name ) ) { |
| 880 |
if ( $param_name == 'id' && empty( $this->id ) ) { |
| 881 |
// ignore this param if its ID and is not set |
| 882 |
} else { |
| 883 |
$params_to_save_with_values[ $param_name ] = $this->prepare_param( $param_name, $this->$param_name ); |
| 884 |
} |
| 885 |
} |
| 886 |
} |
| 887 |
if ( property_exists( $this, 'updated_at' ) && isset( $this->updated_at ) ) { |
| 888 |
$params_to_save_with_values['updated_at'] = $this->updated_at; |
| 889 |
} |
| 890 |
if ( property_exists( $this, 'created_at' ) && isset( $this->created_at ) ) { |
| 891 |
$params_to_save_with_values['created_at'] = $this->created_at; |
| 892 |
} |
| 893 |
|
| 894 |
return $params_to_save_with_values; |
| 895 |
} |
| 896 |
|
| 897 |
|
| 898 |
protected function is_encrypted_param( $param_name ) { |
| 899 |
return in_array( $param_name, $this->encrypted_params( $param_name ) ); |
| 900 |
} |
| 901 |
|
| 902 |
protected function prepare_param( $param_name, $value ) { |
| 903 |
if ( ! empty( $value ) ) { |
| 904 |
if ( $this->is_encrypted_param( $param_name ) ) { |
| 905 |
$value = OsEncryptHelper::encrypt_value( $value ); |
| 906 |
} else { |
| 907 |
$value = $value; |
| 908 |
} |
| 909 |
} |
| 910 |
|
| 911 |
return $value; |
| 912 |
} |
| 913 |
|
| 914 |
protected function encrypted_params() { |
| 915 |
return []; |
| 916 |
} |
| 917 |
|
| 918 |
protected function params_to_sanitize() { |
| 919 |
return []; |
| 920 |
} |
| 921 |
|
| 922 |
public function generate_first_level_data_vars(): array { |
| 923 |
return []; |
| 924 |
} |
| 925 |
|
| 926 |
public function generate_data_vars(): array { |
| 927 |
return []; |
| 928 |
} |
| 929 |
|
| 930 |
public function get_data_vars( $force_regenerate = false ): array { |
| 931 |
$data = ( $force_regenerate || empty( $this->data_vars ) ) ? $this->generate_data_vars() : $this->data_vars; |
| 932 |
|
| 933 |
return apply_filters( 'latepoint_model_view_as_data', $data, $this ); |
| 934 |
} |
| 935 |
|
| 936 |
public function get_first_level_data_vars( $force_regenerate = false ): array { |
| 937 |
$data = ( $force_regenerate || empty( $this->first_level_data_vars ) ) ? $this->generate_first_level_data_vars() : $this->first_level_data_vars; |
| 938 |
|
| 939 |
return apply_filters( 'latepoint_model_view_as_first_level_data', $data, $this ); |
| 940 |
} |
| 941 |
|
| 942 |
protected function properties_to_query(): array { |
| 943 |
$properties = []; |
| 944 |
|
| 945 |
return $properties; |
| 946 |
} |
| 947 |
|
| 948 |
public function get_properties_to_query(): array { |
| 949 |
$properties = $this->properties_to_query(); |
| 950 |
|
| 951 |
/** |
| 952 |
* List of model properties that are allowed to be queried by the condition form in processes |
| 953 |
* |
| 954 |
* @param {array} $properties List of model properties allowed to be queried |
| 955 |
* @param {OsModel} $this Instance of model that properties will be available for |
| 956 |
* @returns {array} List of model properties that are allowed to be queried |
| 957 |
* |
| 958 |
* @since 4.7.0 |
| 959 |
* @hook latepoint_model_properties_to_query |
| 960 |
* |
| 961 |
*/ |
| 962 |
return apply_filters( 'latepoint_model_properties_to_query', $properties, $this ); |
| 963 |
} |
| 964 |
|
| 965 |
// params that are allowed to be mass assigned using set_data method |
| 966 |
protected function allowed_params( $role = 'admin' ) { |
| 967 |
$allowed_params = []; |
| 968 |
|
| 969 |
return $allowed_params; |
| 970 |
} |
| 971 |
|
| 972 |
protected function params_to_save( $role = 'admin' ) { |
| 973 |
$allowed_params = []; |
| 974 |
|
| 975 |
return $allowed_params; |
| 976 |
} |
| 977 |
|
| 978 |
public function get_params_to_save( $role = 'admin' ) { |
| 979 |
return $this->params_to_save( $role ); |
| 980 |
} |
| 981 |
|
| 982 |
public function get_allowed_params( $role = 'admin' ) { |
| 983 |
$allowed_params = $this->allowed_params( $role ); |
| 984 |
|
| 985 |
/** |
| 986 |
* List of model params that are allowed to be mass assigned to a child of <code>OsModel</code> |
| 987 |
* |
| 988 |
* @param {array} $allowed_params List of model params being filtered |
| 989 |
* @param {OsModel} $this Instance of model that the allowed params apply to |
| 990 |
* @param {string} $role User role that the allowed params apply to |
| 991 |
* @returns {array} List of model params that are allowed to be mass assigned |
| 992 |
* |
| 993 |
* @since 1.0.0 |
| 994 |
* @hook latepoint_model_allowed_params |
| 995 |
* |
| 996 |
*/ |
| 997 |
return apply_filters( 'latepoint_model_allowed_params', $allowed_params, $this, $role ); |
| 998 |
} |
| 999 |
|
| 1000 |
|
| 1001 |
|
| 1002 |
|
| 1003 |
|
| 1004 |
|
| 1005 |
// ------------------------- |
| 1006 |
// Error handling |
| 1007 |
// ------------------------- |
| 1008 |
|
| 1009 |
|
| 1010 |
// CLEAR |
| 1011 |
protected function clear_error() { |
| 1012 |
$this->error = false; |
| 1013 |
} |
| 1014 |
|
| 1015 |
|
| 1016 |
// ADD |
| 1017 |
public function add_error( $code, $error_message = 'Field is not valid.', $data = '' ) { |
| 1018 |
if ( is_array( $error_message ) ) { |
| 1019 |
$error_message = implode( ', ', $error_message ); |
| 1020 |
} |
| 1021 |
if ( is_wp_error( $this->get_error() ) ) { |
| 1022 |
$this->get_error()->add( $code, $error_message, $data ); |
| 1023 |
} else { |
| 1024 |
$this->error = new WP_Error( $code, $error_message, $data ); |
| 1025 |
} |
| 1026 |
} |
| 1027 |
|
| 1028 |
|
| 1029 |
// GET DATA |
| 1030 |
public function get_error_data( $code ) { |
| 1031 |
if ( is_wp_error( $this->get_error() ) ) { |
| 1032 |
return $this->get_error()->get_error_data( $code ); |
| 1033 |
} else { |
| 1034 |
return false; |
| 1035 |
} |
| 1036 |
} |
| 1037 |
|
| 1038 |
// GET |
| 1039 |
public function get_error() { |
| 1040 |
return $this->error; |
| 1041 |
} |
| 1042 |
|
| 1043 |
|
| 1044 |
// CHECK |
| 1045 |
public function has_validation_error() { |
| 1046 |
if ( is_wp_error( $this->get_error() ) && $this->get_error()->get_error_messages( 'validation' ) ) { |
| 1047 |
return true; |
| 1048 |
} else { |
| 1049 |
return false; |
| 1050 |
} |
| 1051 |
} |
| 1052 |
|
| 1053 |
|
| 1054 |
// GET MESSAGES |
| 1055 |
public function get_error_messages( $code = false ) { |
| 1056 |
if ( is_wp_error( $this->get_error() ) ) { |
| 1057 |
return $this->get_error()->get_error_messages( $code ); |
| 1058 |
} else { |
| 1059 |
return []; |
| 1060 |
} |
| 1061 |
} |
| 1062 |
|
| 1063 |
|
| 1064 |
|
| 1065 |
|
| 1066 |
// ------------------------- |
| 1067 |
// Validations |
| 1068 |
// ------------------------- |
| 1069 |
|
| 1070 |
public function validate( $alternative_validation = false, $skip_properties = [] ): bool { |
| 1071 |
$this->clear_error(); |
| 1072 |
$properties_to_validate = $this->properties_to_validate( $alternative_validation ); |
| 1073 |
foreach ( $properties_to_validate as $property_name => $validations ) { |
| 1074 |
if ( $skip_properties && in_array( $property_name, $skip_properties ) ) { |
| 1075 |
continue; |
| 1076 |
} |
| 1077 |
foreach ( $validations as $validation ) { |
| 1078 |
$validation_function = 'validates_' . $validation; |
| 1079 |
if ( ! method_exists( $this, $validation_function ) ) { |
| 1080 |
continue; |
| 1081 |
} |
| 1082 |
$validation_result = $this->$validation_function( $property_name ); |
| 1083 |
if ( is_wp_error( $validation_result ) ) { |
| 1084 |
$this->add_error( 'validation', $validation_result->get_error_message( $property_name ) ); |
| 1085 |
} |
| 1086 |
} |
| 1087 |
} |
| 1088 |
/** |
| 1089 |
* Custom validations to apply to a child of <code>OsModel</code> |
| 1090 |
* |
| 1091 |
* @param {OsModel} $this Instance of model to apply custom validations to |
| 1092 |
* @param {bool} $alternative_validation True if applying alternative validations, false otherwise |
| 1093 |
* |
| 1094 |
* @since 1.0.0 |
| 1095 |
* @hook latepoint_model_validate |
| 1096 |
* |
| 1097 |
*/ |
| 1098 |
do_action( 'latepoint_model_validate', $this, $alternative_validation, $skip_properties ); |
| 1099 |
if ( $this->has_validation_error() ) { |
| 1100 |
return false; |
| 1101 |
} else { |
| 1102 |
return true; |
| 1103 |
} |
| 1104 |
} |
| 1105 |
|
| 1106 |
|
| 1107 |
protected function properties_to_validate() { |
| 1108 |
return []; |
| 1109 |
} |
| 1110 |
|
| 1111 |
protected function validates_email( $property ) { |
| 1112 |
if ( empty( $this->$property ) || OsUtilHelper::is_valid_email( $this->$property ) ) { |
| 1113 |
return true; |
| 1114 |
} else { |
| 1115 |
// translators: %s is the property name for a model |
| 1116 |
return new WP_Error( $property, sprintf( __( '%s is not valid', 'latepoint' ), $this->get_property_nice_name( $property ) ) ); |
| 1117 |
} |
| 1118 |
} |
| 1119 |
|
| 1120 |
protected function validates_presence( $property ) { |
| 1121 |
$validation_result = ( isset( $this->$property ) && ! empty( $this->$property ) ); |
| 1122 |
if ( $validation_result ) { |
| 1123 |
return true; |
| 1124 |
} else { |
| 1125 |
// translators: %s is the property name for a model |
| 1126 |
return new WP_Error( $property, sprintf( __( '%s can not be blank', 'latepoint' ), $this->get_property_nice_name( $property ) ) ); |
| 1127 |
} |
| 1128 |
} |
| 1129 |
|
| 1130 |
protected function validates_uniqueness( $property ) { |
| 1131 |
if ( isset( $this->$property ) && ! empty( $this->$property ) ) { |
| 1132 |
if ( $this->is_new_record() ) { |
| 1133 |
$query = $this->prepare( |
| 1134 |
'SELECT %i FROM %i WHERE %i = %s LIMIT 1', |
| 1135 |
[ |
| 1136 |
$property, |
| 1137 |
$this->table_name, |
| 1138 |
$property, |
| 1139 |
$this->$property, |
| 1140 |
] |
| 1141 |
); |
| 1142 |
} else { |
| 1143 |
$query = $this->prepare( |
| 1144 |
'SELECT %i FROM %i WHERE %i = %s AND id != %d LIMIT 1', |
| 1145 |
[ |
| 1146 |
$property, |
| 1147 |
$this->table_name, |
| 1148 |
$property, |
| 1149 |
$this->$property, |
| 1150 |
$this->id, |
| 1151 |
] |
| 1152 |
); |
| 1153 |
} |
| 1154 |
$items = $this->db->get_results( $query, ARRAY_A ); |
| 1155 |
if ( $items ) { |
| 1156 |
// translators: %s is the property name for a model |
| 1157 |
return new WP_Error( $property, sprintf( __( '%s has to be unique', 'latepoint' ), $this->get_property_nice_name( $property ) ) ); |
| 1158 |
} |
| 1159 |
} |
| 1160 |
|
| 1161 |
return true; |
| 1162 |
} |
| 1163 |
|
| 1164 |
public function get_validations_for_property( string $property ): array { |
| 1165 |
$validations = $this->properties_to_validate(); |
| 1166 |
|
| 1167 |
return $validations[ $property ] ?? []; |
| 1168 |
} |
| 1169 |
|
| 1170 |
|
| 1171 |
public function format_created_datetime_rfc3339() { |
| 1172 |
$datetime = OsTimeHelper::date_from_db( $this->created_at ); |
| 1173 |
if ( ! $datetime ) { |
| 1174 |
return 'invalid date'; |
| 1175 |
} |
| 1176 |
$datetime->setTimezone( new DateTimeZone( 'UTC' ) ); |
| 1177 |
|
| 1178 |
return $datetime->format( \DateTime::RFC3339 ); |
| 1179 |
} |
| 1180 |
} |
| 1181 |
|