<?php #[AllowDynamicProperties] class OsModel { protected $error, $db; public $nice_names = []; protected $comparisons = array( '>=', '<=', '<', '>', '!=', 'LIKE' ); protected $conditions = []; protected $limit = false; protected $offset = false; protected $select_args = []; protected $order_args = false; protected $group_args = false; protected $having_args = false; protected $joins = []; public $data_vars = []; public $first_level_data_vars = []; public $form_id = false; public $last_query = ''; protected $meta_class = false; public $meta = false; public $table_name = ''; public $join_attributes = []; function __construct( $id = false ) { $this->error = false; global $wpdb; $this->db = $wpdb; if ( $id ) { $this->load_by_id( $id ); } } public function __get( $property ) { $method = "get_$property"; if ( method_exists( $this, $method ) ) { return $this->$method(); } } public function exists() { return ( isset( $this->id ) && ! empty( $this->id ) ); } public function formatted_created_date( $format = false, $default = 'n/a' ) { if ( ! $format ) { $format = OsSettingsHelper::get_readable_date_format(); } if ( property_exists( $this, 'created_at' ) && isset( $this->created_at ) && ! empty( $this->created_at ) ) { $date = new OsWpDateTime( $this->created_at, new DateTimeZone('UTC') ); return $date->format( $format ); } else { return $default; } } public function readable_created_date() : string { try{ return OsTimeHelper::get_readable_date( new OsWpDateTime( $this->created_at, new DateTimeZone('UTC') ) ); }catch( Exception $e ) { return 'n/a'; } } public function prepare( $query, $values ) { if ( empty( $values ) ) { return $query; } else { return $this->db->prepare( $query, $values ); } } /** * * Clears all GROUP BY arguments * * @return $this OsModel */ public function clear_group_by(): OsModel { $this->group_args = ''; return $this; } public function group_by( $group_args ) { if ( $this->group_args ) { $this->group_args = implode( ',', array( $this->group_args, $group_args ) ); } else { $this->group_args = $group_args; } return $this; } public function get_group_args() { if ( $this->group_args ) { return 'GROUP BY ' . $this->group_args; } else { return ''; } } public function clear_having(): OsModel { $this->having_args = ''; return $this; } public function get_having_args(): string { if ( $this->having_args ) { return 'HAVING ' . $this->having_args; } return ''; } public function having( $having_args ) { if ( $this->having_args ) { $this->having_args = implode( ',', array( $this->having_args, $having_args ) ); } else { $this->having_args = $having_args; } return $this; } public function order_by( $order_args ) { if ( $this->order_args ) { $this->order_args = implode( ',', array( $this->order_args, $order_args ) ); } else { $this->order_args = $order_args; } return $this; } public function get_order_args() { if ( $this->order_args ) { return 'ORDER BY ' . $this->order_args; } else { return ''; } } public static function where_in_array_to_string( $array_of_values ) { $clean_string = ''; if ( is_array( $array_of_values ) ) { $array_of_values = array_map( function ( $v ) { return "'" . esc_sql( $v ) . "'"; }, $array_of_values ); $clean_string = ' (' . implode( ',', $array_of_values ) . ') '; } return $clean_string; } /** * @param array $conditions * * @return $this */ public function filter_where_conditions( array $allowed_conditions ): OsModel { foreach ( $allowed_conditions as $condition_name => $allowed_condition_value ) { if ( empty( $this->conditions[ $condition_name ] ) ) { $this->conditions[ $condition_name ] = $allowed_condition_value; } else { // convert both to arrays to compare $current_value = is_array( $this->conditions[ $condition_name ] ) ? $this->conditions[ $condition_name ] : OsUtilHelper::explode_and_trim( $this->conditions[ $condition_name ] ); $allowed_value = is_array( $allowed_condition_value ) ? $allowed_condition_value : OsUtilHelper::explode_and_trim( $allowed_condition_value ); $this->conditions[ $condition_name ] = array_intersect( $current_value, $allowed_value ); } } return $this; } public function where( $conditions ) { if ( empty( $conditions ) ) { return $this; } $this->conditions = array_merge( $this->conditions, $conditions ); return $this; } public function where_in( $column, $array_of_values ) { $condition = array( "{$column} IN " => $array_of_values ); $this->conditions = array_merge( $this->conditions, $condition ); return $this; } public function where_not_in( $column, $array_of_values ) { $condition = array( "{$column} NOT IN " => $array_of_values ); $this->conditions = array_merge( $this->conditions, $condition ); return $this; } public function join( $table, $on_args, $type = '' ) { $this->joins[] = [ 'join_table' => $table, 'join_on_args' => $on_args, 'join_type' => in_array( $type, [ 'left', 'right' ] ) ? $type : '' ]; return $this; } public function get_join_string(): string { $join_query = ''; if ( ! empty( $this->joins ) ) { foreach ( $this->joins as $join_data ) { if ( empty( $join_data['join_table'] ) || empty( $join_data['join_on_args'] ) ) { continue; } $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'] ); } } return $join_query; } private function build_join_args_query( $join_table, $join_on_args ) { $join_args_query_arr = []; foreach ( $join_on_args as $column_one => $column_two ) { if ( is_array( $column_two ) ) { $in_values = implode( ',', $column_two ); $join_args_query_arr[] = "{$join_table}.{$column_one} IN ({$in_values})"; } else { $join_args_query_arr[] = "{$join_table}.{$column_one} = {$column_two}"; } } return implode( ' AND ', $join_args_query_arr ); } /** * * Clears all SELECT arguments * * @return $this OsModel */ public function clear_select(): OsModel { $this->select_args = []; return $this; } /** * * Adds arguments to SELECT query * * @param $select_args Array|string or comma separated String of arguments * * @return $this OsModel */ public function select( $select_args ): OsModel { if ( ! is_array( $select_args ) ) { $select_args = OsUtilHelper::explode_and_trim( $select_args ); } if ( ! empty( $select_args ) ) { $this->select_args = array_merge( $this->select_args, $select_args ); } return $this; } public function build_select_args_string(): string { $select_args = $this->get_select_args(); if ( empty( $select_args ) ) { return '*'; } else { return implode( ',', array_unique( $this->select_args ) ); } } public function get_select_args(): array { return $this->select_args; } /** * Eager load meta key-value pairs associated with this model * * @param array $meta_keys * * @return $this */ public function with_meta( array $meta_keys = [] ): OsModel { $this->meta = []; $meta_class = $this->meta_class; if ( $this->exists() && $meta_class && class_exists( $meta_class ) ) { /** @var OsMetaModel $meta_object */ $meta_object = new $meta_class(); if ( ! empty( $meta_keys ) ) { foreach ( $meta_keys as $meta_key ) { $this->meta[] = [ $meta_key => $meta_object->get_by_key( $meta_key, $this->id ) ]; } } else { $this->meta = $meta_object->get_by_object_id( $this->id ); } } return $this; } public function set_limit( $limit ) { $this->limit = $limit; return $this; } public function count() { $count = $this->clear_select()->clear_group_by()->clear_having()->select( 'COUNT(DISTINCT(' . $this->table_name . '.id)) as total' )->set_limit( 1 )->get_results(); $total = ( $count ) ? $count->total : 0; return $total; } public function set_offset( $offset ) { $this->offset = $offset; return $this; } protected function with_table_name( $column ) { if ( ! is_numeric( $column ) && ! in_array( $column, [ 'AND', 'OR' ] ) && ( strpos( $column, '(' ) === false ) && ( strpos( $column, '.' ) === false ) ) { return $this->table_name . '.' . $column; } else { return $column; } } protected function build_conditions_query( $conditions, $logical_operator = 'AND' ) { $where_conditions = []; $where_values = []; $sql_query = ''; $index = 0; if ( $conditions ) { foreach ( $conditions as $column => $value ) { $temp_query = false; if ( $column == 'OR' || $column == 'AND' ) { $sql_query .= '('; $conditions_and_values = $this->build_conditions_query( $value, $column ); $sql_query .= $conditions_and_values[0]; $where_values = array_merge( $where_values, $conditions_and_values[1] ); $sql_query .= ')'; } else { // Check if its a comparison condition e.g. <, >, <=, >= etc... foreach ( $this->comparisons as $comparison ) { if ( strpos( $column, $comparison ) ) { $column = str_replace( $comparison, '', $column ); $temp_query = $this->with_table_name( $column ) . $comparison . ' %s'; } } // WHERE IN query if ( strpos( $column, ' NOT IN' ) && is_array( $value ) ) { $temp_query = $this->with_table_name( $column ) . OsModel::where_in_array_to_string( $value ); } elseif ( strpos( $column, ' IN' ) && is_array( $value ) ) { $temp_query = $this->with_table_name( $column ) . OsModel::where_in_array_to_string( $value ); } elseif ( is_array( $value ) && ( isset( $value['OR'] ) || isset( $value['AND'] ) ) ) { // IS ARRAY AND OR foreach ( $value as $condition_and_or => $condition_values ) { $temp_query .= '('; $sub_queries = []; foreach ( $condition_values as $condition_key => $condition_value ) { if ( is_string( $condition_key ) && is_string( $column ) ) { $temp_key = $this->with_table_name( $column ) . $condition_key; $sub_conditions = [ $temp_key => $condition_value ]; } elseif ( is_string( $condition_key ) ) { $sub_conditions = [ $this->with_table_name( $condition_key ) => $condition_value ]; } else { $sub_conditions = [ $column => $condition_value ]; } $conditions_and_values = $this->build_conditions_query( $sub_conditions, $condition_and_or ); $sub_queries[] = $conditions_and_values[0]; $where_values = array_merge( $where_values, $conditions_and_values[1] ); } $temp_query .= implode( ' ' . $condition_and_or . ' ', $sub_queries ); $temp_query .= ')'; } } elseif ( $value === 'IS NULL' ) { // IS NULL $temp_query = $this->with_table_name( $column ) . ' IS NULL '; } elseif ( $value === 'IS NOT NULL' ) { // IS NOT NULL $temp_query = $this->with_table_name( $column ) . ' IS NOT NULL '; } elseif ( is_array( $value ) && ! empty( $value ) ) { $temp_query = $this->with_table_name( $column ) . ' IN ' . OsModel::where_in_array_to_string( $value ); } else { // Add to list of query values if ( is_array( $value ) ) { $where_values[] = OsModel::where_in_array_to_string( $value ); } else { $where_values[] = $value; } } if ( $temp_query ) { $sql_query .= $temp_query; } else { $sql_query .= $this->with_table_name( $column ) . '= %s'; } } $index ++; if ( $index < count( $conditions ) ) { $sql_query .= ' ' . $logical_operator . ' '; } } } return array( $sql_query, $where_values ); } public function escape_by_ref( &$string ) { $this->db->escape_by_ref( $string ); } public function get_results( $results_type = OBJECT ) { $conditions_and_values = $this->build_conditions_query( $this->conditions ); if ( $conditions_and_values[0] ) { $where_query = 'WHERE ' . $conditions_and_values[0]; } else { $where_query = ''; } if ( $this->limit ) { $limit_query = ' LIMIT %d'; $conditions_and_values[1][] = $this->limit; } else { $limit_query = ''; } if ( $this->offset ) { $offset_query = ' OFFSET %d'; $conditions_and_values[1][] = $this->offset; } else { $offset_query = ''; } $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; $this->last_query = vsprintf( $query, $conditions_and_values[1] ); OsDebugHelper::log_query( $this->last_query ); $items = $this->db->get_results( $this->prepare( $query, $conditions_and_values[1] ) , $results_type ); if ( ( $this->limit == 1 ) && isset( $items[0] ) ) { $items = $items[0]; } return $items; } public function get_query_results( $query, $values = [], $results_type = OBJECT ) { $this->last_query = $query; $items = $this->db->get_results( $this->prepare( $query, $values ) , $results_type ); OsDebugHelper::log_query( $query ); return $items; } public function reset_conditions() { $this->conditions = []; } /** * @param $query * @param $values * * @return static|static[] */ public function get_results_as_models( $query = false, $values = [] ) { if ( $query ) { $items = $this->get_query_results( $query, $values ); } else { $items = $this->get_results(); } $models = []; if ( empty( $items ) ) { return []; } if ( $this->limit == 1 ) { $items = [ $items ]; } foreach ( $items as $item ) { $current_class_name = get_class( $this ); $model = new $current_class_name(); foreach ( $item as $prop_name => $prop_value ) { $model->$prop_name = $prop_value; } /** * A child of <code>OsModel</code> is about to be added to the result set * * @param {OsModel} $model Instance of model that should be filtered * @returns {OsModel} Instance of model that has been filtered * * @since 1.0.0 * @hook latepoint_get_results_as_models * */ $model = apply_filters( 'latepoint_get_results_as_models', $model ); if ( $model ) { $models[] = $model; } } $this->reset_conditions(); if ( $this->limit == 1 && isset( $models[0] ) ) { $models = $models[0]; } return $models; } public function filter_allowed_records(): OsModel { return $this; } public function get_image_url( $size = 'thumbnail' ) { $url = OsImageHelper::get_image_url_by_id( $this->image_id, $size ); return $url; } public function set_data( $data, $role = 'admin', $sanitize = true ) { $data = $this->prepare_data_before_it_is_set( $data ); /** * Data/Params are being prepared to be set on a child of <code>OsModel</code> * * @param {OsModel} $this Instance of model that data is to be set on * @param {array} $data Array of data/params to be set * * @since 1.0.0 * @hook latepoint_model_prepare_set_data * */ do_action( 'latepoint_model_prepare_set_data', $this, $data ); if ( is_array( $data ) ) { // array passed // if ID is passed and model not loaded from db yet - load data from db if ( isset( $data['id'] ) && is_numeric( $data['id'] ) && property_exists( $this, 'id' ) && $this->is_new_record() ) { $this->load_by_id( $data['id'] ); } foreach ( $this->get_allowed_params( $role ) as $param ) { if ( isset( $data[ $param ] ) ) { $this->$param = $sanitize ? $this->sanitize_param( $param, $data[ $param ] ) : $data[ $param ]; } } } else { // object passed // if ID is passed and model not loaded from db yet - load data from db if ( isset( $data->id ) && is_numeric( $data->id ) && property_exists( $this, 'id' ) && $this->is_new_record() ) { $this->load_by_id( $data->id ); } foreach ( $this->get_allowed_params( $role ) as $param ) { if ( isset( $data->$param ) ) { $this->$param = $sanitize ? $this->sanitize_param( $param, $data->$param ) : $data->$param; } } } /** * Data/Params have been set on a child of <code>OsModel</code> * * @param {OsModel} $this Instance of model that data was set on * @param {array} $data Array of data/params that was set * * @since 1.0.0 * @hook latepoint_model_set_data * */ do_action( 'latepoint_model_set_data', $this, $data ); $this->after_data_was_set( $data ); return $this; } /** * @return void * * Useful for child classes, to do something after a data is set */ public function after_data_was_set( $data ) { } /** * @return void * * Useful for child classes, to do something after a data is set */ public function prepare_data_before_it_is_set( $data ) { return $data; } public function delete_where( $where = false, $where_format = null ) { if ( is_array( $where ) && $this->db->delete( $this->table_name, $where, $where_format ) ) { return true; } else { return false; } } public function delete( $id = false ) { if ( ! $id && isset( $this->id ) ) { $id = $this->id; } if ( $id && $this->db->delete( $this->table_name, array( 'id' => $id ), array( '%d' ) ) ) { /** * A child of <code>OsModel</code> has been deleted * * @param {OsModel} $this Instance of model that has been deleted * @param {integer} $id ID of model instance that has been deleted * * @since 4.6.3 * @hook latepoint_model_deleted * */ do_action( 'latepoint_model_deleted', $this, $id ); return true; } else { return false; } } public function load_from_row_data( $row_data ) { foreach ( $row_data as $key => $field ) { if ( property_exists( $this, $key ) ) { $this->$key = $field; } } } public function load_by_id( $id ) { if ( filter_var( $id, FILTER_VALIDATE_INT ) === false ) { return false; } $query = $this->prepare( 'SELECT ' . $this->build_select_args_string() . ' FROM ' . $this->table_name . ' WHERE id = %d', $id ); $result_row = $this->db->get_row( $query, ARRAY_A ); if ( $result_row ) { foreach ( $result_row as $row_key => $row_value ) { if ( property_exists( $this, $row_key ) ) { $this->$row_key = $row_value; } } /** * A child of <code>OsModel</code> has been loaded from the DB by its ID * * @param {OsModel} $this Instance of model that has been loaded * @returns {OsModel} Instance of model that has been filtered * * @since 1.0.0 * @hook latepoint_model_loaded_by_id * */ return apply_filters( 'latepoint_model_loaded_by_id', $this ); } else { return false; } } /** * * Generates an ID that is used in a form for quick editing. Returns ID if exists or returns a "new_HASH" to be used * as ID to indicate that it's a new record * * @return string */ public function get_form_id(): string { if ( $this->is_new_record() ) { if ( empty( $this->form_id ) ) { $this->form_id = OsUtilHelper::generate_form_id(); } } else { $this->form_id = $this->id; } return $this->form_id; } public function is_new_record() { if ( $this->id ) { return false; } else { return true; } } public function get_field( $field_name ) { return $this->$field_name; } public function set_field( $field_name, $field_value ) { $this->$field_name = $field_value; } protected function before_save() { } protected function before_create() { } // updates array of attributes public function update_attributes( $data, $sanitize = true ) { if ( $this->is_new_record() ) { return false; } $prepared_data = []; foreach ( $data as $key => $value ) { if ( property_exists( $this, $key ) ) { if ( $sanitize && array_key_exists( $key, $this->params_to_sanitize() ) ) { $value = OsParamsHelper::sanitize_param( $value, $this->params_to_sanitize()[ $key ] ); } $this->$key = $value; // encrypt value if it needs to be encrypted, however the model object itself stores an un-encrypted value if ( in_array( $key, $this->encrypted_params() ) ) { $value = OsEncryptHelper::encrypt_value(); } $prepared_data[ $key ] = $value; } } if ( empty( $prepared_data ) ) { return false; } else { $now = OsTimeHelper::now_datetime_in_format( LATEPOINT_DATETIME_DB_FORMAT ); if ( property_exists( $this, 'updated_at' ) ) { $prepared_data['updated_at'] = $now; } if ( false === $this->db->update( $this->table_name, $prepared_data, array( 'id' => $this->id ) ) ) { $this->add_error( 'update_error', $this->db->last_error ); return false; } else { if ( property_exists( $this, 'updated_at' ) ) { $this->updated_at = $now; } OsDebugHelper::log_query( $this->db->last_query ); return true; } } } protected function set_defaults() { } // searches list of params that need to be sanitised and returns sanitised value protected function sanitize_param( $param_name, $value ) { if ( $this->params_to_sanitize() && is_array( $this->params_to_sanitize() ) && array_key_exists( $param_name, $this->params_to_sanitize() ) ) { $value = OsParamsHelper::sanitize_param( $value, $this->params_to_sanitize()[ $param_name ] ); } return $value; } public function prepare_and_validate($alternative_validation = false, $skip_properties = [] ) : bool{ try { $this->set_defaults(); $this->before_save(); if($this->validate( $alternative_validation, $skip_properties )){ return true; }else{ return false; } } catch ( Exception $e ) { $this->add_error( 'validate_exception', $e->getMessage() ); return false; } } public function save( $alternative_validation = false, $skip_validation = false ) { try { $this->set_defaults(); $this->before_save(); if ( $skip_validation || $this->validate( $alternative_validation ) ) { if ( property_exists( $this, 'updated_at' ) ) { $this->updated_at = OsTimeHelper::now_datetime_in_format( LATEPOINT_DATETIME_DB_FORMAT ); } if ( $this->is_new_record() ) { // New Record (insert) $this->before_create(); if ( property_exists( $this, 'created_at' ) ) { $this->created_at = OsTimeHelper::now_datetime_in_format( LATEPOINT_DATETIME_DB_FORMAT ); } if ( false === $this->db->insert( $this->table_name, $this->get_params_to_save_with_values() ) && property_exists( $this, 'id' ) ) { $this->add_error( 'insert_error', $this->db->last_error ); return false; } else { OsDebugHelper::log_query( $this->db->last_query ); $this->id = $this->db->insert_id; } } else { // Existing record (update) if ( false === $this->db->update( $this->table_name, $this->get_params_to_save_with_values(), array( 'id' => $this->id ) ) ) { $this->add_error( 'update_error', $this->db->last_error ); return false; } else { OsDebugHelper::log_query( $this->db->last_query ); } } /** * A child of <code>OsModel</code> has been saved to the DB * * @param {OsModel} $this Instance of model that has been saved * * @since 1.0.0 * @hook latepoint_model_save * */ do_action( 'latepoint_model_save', $this ); } else { return false; } return true; } catch ( Exception $e ) { $this->add_error( 'save_exception', $e->getMessage() ); return false; } } protected function get_property_nice_name( $property ) { if ( isset( $this->nice_names[ $property ] ) ) { return $this->nice_names[ $property ]; } else { return ucwords( str_replace( "_", " ", $property ) ); } } protected function get_params_to_save_with_values( $role = 'admin' ) { $params_to_save = $this->get_params_to_save( $role ); $params_to_save_with_values = []; foreach ( $params_to_save as $param_name ) { if ( property_exists( $this, $param_name ) ) { if ( $param_name == 'id' && empty( $this->id ) ) { // ignore this param if its ID and is not set } else { $params_to_save_with_values[ $param_name ] = $this->prepare_param( $param_name, $this->$param_name ); } } } if ( property_exists( $this, 'updated_at' ) && isset( $this->updated_at ) ) { $params_to_save_with_values['updated_at'] = $this->updated_at; } if ( property_exists( $this, 'created_at' ) && isset( $this->created_at ) ) { $params_to_save_with_values['created_at'] = $this->created_at; } return $params_to_save_with_values; } protected function is_encrypted_param( $param_name ) { return in_array( $param_name, $this->encrypted_params( $param_name ) ); } protected function prepare_param( $param_name, $value ) { if ( ! empty( $value ) ) { if ( $this->is_encrypted_param( $param_name ) ) { $value = OsEncryptHelper::encrypt_value( $value ); } else { $value = $value; } } return $value; } protected function encrypted_params() { return []; } protected function params_to_sanitize() { return []; } public function generate_first_level_data_vars() : array{ return []; } public function generate_data_vars(): array { return []; } public function get_data_vars( $force_regenerate = false ): array { $data = ( $force_regenerate || empty( $this->data_vars ) ) ? $this->generate_data_vars() : $this->data_vars; return apply_filters( 'latepoint_model_view_as_data', $data, $this ); } public function get_first_level_data_vars( $force_regenerate = false ): array { $data = ( $force_regenerate || empty( $this->first_level_data_vars ) ) ? $this->generate_first_level_data_vars() : $this->first_level_data_vars; return apply_filters( 'latepoint_model_view_as_first_level_data', $data, $this ); } protected function properties_to_query(): array { $properties = []; return $properties; } public function get_properties_to_query(): array { $properties = $this->properties_to_query(); /** * List of model properties that are allowed to be queried by the condition form in processes * * @param {array} $properties List of model properties allowed to be queried * @param {OsModel} $this Instance of model that properties will be available for * @returns {array} List of model properties that are allowed to be queried * * @since 4.7.0 * @hook latepoint_model_properties_to_query * */ return apply_filters( 'latepoint_model_properties_to_query', $properties, $this ); } // params that are allowed to be mass assigned using set_data method protected function allowed_params( $role = 'admin' ) { $allowed_params = []; return $allowed_params; } protected function params_to_save( $role = 'admin' ) { $allowed_params = []; return $allowed_params; } public function get_params_to_save( $role = 'admin' ) { return $this->params_to_save( $role ); } public function get_allowed_params( $role = 'admin' ) { $allowed_params = $this->allowed_params( $role ); /** * List of model params that are allowed to be mass assigned to a child of <code>OsModel</code> * * @param {array} $allowed_params List of model params being filtered * @param {OsModel} $this Instance of model that the allowed params apply to * @param {string} $role User role that the allowed params apply to * @returns {array} List of model params that are allowed to be mass assigned * * @since 1.0.0 * @hook latepoint_model_allowed_params * */ return apply_filters( 'latepoint_model_allowed_params', $allowed_params, $this, $role ); } // ------------------------- // Error handling // ------------------------- // CLEAR protected function clear_error() { $this->error = false; } // ADD public function add_error( $code, $error_message = 'Field is not valid.', $data = '' ) { if ( is_array( $error_message ) ) { $error_message = implode( ', ', $error_message ); } if ( is_wp_error( $this->get_error() ) ) { $this->get_error()->add( $code, $error_message, $data ); } else { $this->error = new WP_Error( $code, $error_message, $data ); } } // GET DATA public function get_error_data( $code ) { if ( is_wp_error( $this->get_error() ) ) { return $this->get_error()->get_error_data( $code ); } else { return false; } } // GET public function get_error() { return $this->error; } // CHECK public function has_validation_error() { if ( is_wp_error( $this->get_error() ) && $this->get_error()->get_error_messages( 'validation' ) ) { return true; } else { return false; } } // GET MESSAGES public function get_error_messages( $code = false ) { if ( is_wp_error( $this->get_error() ) ) { return $this->get_error()->get_error_messages( $code ); } else { return []; } } // ------------------------- // Validations // ------------------------- public function validate( $alternative_validation = false, $skip_properties = [] ) : bool { $this->clear_error(); foreach ( $this->properties_to_validate( $alternative_validation ) as $property_name => $validations ) { if($skip_properties && in_array( $property_name, $skip_properties )) continue; foreach ( $validations as $validation ) { $validation_function = 'validates_' . $validation; if ( ! method_exists( $this, $validation_function ) ) { continue; } $validation_result = $this->$validation_function( $property_name ); if ( is_wp_error( $validation_result ) ) { $this->add_error( 'validation', $validation_result->get_error_message( $property_name ) ); } } } /** * Custom validations to apply to a child of <code>OsModel</code> * * @param {OsModel} $this Instance of model to apply custom validations to * @param {bool} $alternative_validation True if applying alternative validations, false otherwise * * @since 1.0.0 * @hook latepoint_model_validate * */ do_action( 'latepoint_model_validate', $this, $alternative_validation, $skip_properties ); if ( $this->has_validation_error() ) { return false; } else { return true; } } protected function properties_to_validate() { return []; } protected function validates_email( $property ) { if ( empty( $this->$property ) || OsUtilHelper::is_valid_email( $this->$property ) ) { return true; } else { // translators: %s is the property name for a model return new WP_Error( $property, sprintf( __( '%s is not valid', 'latepoint' ), $this->get_property_nice_name( $property ) ) ); } } protected function validates_presence( $property ) { $validation_result = ( isset( $this->$property ) && ! empty( $this->$property ) ); if ( $validation_result ) { return true; } else { // translators: %s is the property name for a model return new WP_Error( $property, sprintf( __( '%s can not be blank', 'latepoint' ), $this->get_property_nice_name( $property ) ) ); } } protected function validates_uniqueness( $property ) { if ( isset( $this->$property ) && ! empty( $this->$property ) ) { if ( $this->is_new_record() ) { $query = $this->prepare( 'SELECT %i FROM %i WHERE %i = %s LIMIT 1', [ $property, $this->table_name, $property, $this->$property ] ); } else { $query = $this->prepare( 'SELECT %i FROM %i WHERE %i = %s AND id != %d LIMIT 1', [ $property, $this->table_name, $property, $this->$property, $this->id ] ); } $items = $this->db->get_results( $query, ARRAY_A ); if ( $items ) { // translators: %s is the property name for a model return new WP_Error( $property, sprintf( __( '%s has to be unique', 'latepoint' ), $this->get_property_nice_name( $property ) ) ); } } return true; } public function get_validations_for_property( string $property ): array { $validations = $this->properties_to_validate(); return $validations[ $property ] ?? []; } public function format_created_datetime_rfc3339() { $datetime = OsTimeHelper::date_from_db( $this->created_at ); if ( ! $datetime ) { return 'invalid date'; } $datetime->setTimezone( new DateTimeZone( "UTC" ) ); return $datetime->format( \DateTime::RFC3339 ); } }