field_names = $field_names; } public function __call( $name, $args ) { foreach ( array( 'positive', 'negative' ) as $kind ) { $suffices = "{$kind}_suffices"; foreach ( self::$$suffices as $suffix ) { foreach ( $this->field_names as $field_name ) { if ( "{$field_name}_{$suffix}" == $name ) { $this->rules[ $field_name ][] = array( 'field' => $field_name, 'rule' => $args[0], 'kind' => $kind, 'args' => array_slice( $args, 1 ), ); return true; } } } } // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error trigger_error( sprintf( /* translators: %s: Method name. */ esc_html__( 'Call to undefined method: %s.', 'glotpress' ), sprintf( '%1$s::%2$s()', esc_html( get_class( $this ) ), esc_html( $name ) ) ), E_USER_ERROR ); } public function run( $thing ) { $this->errors = array(); $verdict = true; foreach ( $this->field_names as $field_name ) { // Do not try to validate missing fields. if ( ! gp_object_has_var( $thing, $field_name ) ) { continue; } $value = $thing->$field_name; $field_verdict = $this->run_on_single_field( $field_name, $value ); $verdict = $verdict && $field_verdict; } return $verdict; } public function run_on_single_field( $field, $value ) { if ( ! isset( $this->rules[ $field ] ) || ! is_array( $this->rules[ $field ] ) ) { // No rules means always valid. return true; } $verdict = true; foreach ( $this->rules[ $field ] as $rule ) { $callback = GP_Validators::get( $rule['rule'] ); if ( is_null( $callback ) ) { // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error trigger_error( sprintf( /* translators: %s: Rule. */ __( 'Non-existent validator: %s', 'glotpress' ), esc_html( $rule['rule'] ) ), WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE ); continue; } $args = $rule['args']; array_unshift( $args, $value ); if ( 'positive' === $rule['kind'] ) { if ( ! $callback['positive']( ...$args ) ) { $this->errors[] = $this->construct_error_message( $rule ); $verdict = false; } } else { if ( null === $callback['negative'] ) { if ( $callback['positive']( ...$args ) ) { $this->errors[] = $this->construct_error_message( $rule ); $verdict = false; } } elseif ( ! $callback['negative']( ...$args ) ) { $this->errors[] = $this->construct_error_message( $rule ); $verdict = false; } } } return $verdict; } public function construct_error_message( $rule ) { $type_field = 'field'; $name_field = $rule['field']; $name_rule = str_replace( '_', ' ', $rule['rule'] ); if ( 1 === preg_match( '/translation_[0-9]/', $name_field ) ) { $type_field = 'textarea'; $name_field = 'Translation ' . ( intval( substr( $name_field, 12 ) ) + 1 ); } if ( 'positive' == $rule['kind'] ) { /* translators: 1: type of a validation field, 2: name of a validation field, 3: validation rule */ return sprintf( __( 'The %1$s %2$s is invalid and should be %3$s!', 'glotpress' ), $type_field, '' . $name_field . '', $name_rule ); } else { // if ( 'negative' == $rule['kind'] ) /* translators: 1: type of a validation field, 2: name of a validation field, 3: validation rule */ return sprintf( __( 'The %1$s %2$s is invalid and should not be %3$s!', 'glotpress' ), $type_field, '' . $name_field . '', $name_rule ); } } } class GP_Validators { static $callbacks = array(); public static function register( $key, $callback, $negative_callback = null ) { // TODO: add data for easier generation of error messages self::$callbacks[ $key ] = array( 'positive' => $callback, 'negative' => $negative_callback, ); } public static function unregister( $key ) { unset( self::$callbacks[ $key ] ); } public static function get( $key ) { return gp_array_get( self::$callbacks, $key, null ); } } GP_Validators::register( 'empty', 'gp_is_empty' ); GP_Validators::register( 'empty_string', 'gp_is_empty_string' ); GP_Validators::register( 'positive_int', 'gp_is_positive_int' ); GP_Validators::register( 'int', 'gp_is_int' ); GP_Validators::register( 'null', 'gp_is_null' ); GP_Validators::register( 'between', 'gp_is_between' ); GP_Validators::register( 'between_exclusive', 'gp_is_between_exclusive' ); GP_Validators::register( 'one_of', 'gp_is_one_of' ); GP_Validators::register( 'consisting_only_of_ASCII_characters', 'gp_is_ascii_string' ); GP_Validators::register( 'starting_and_ending_with_a_word_character', 'gp_is_starting_and_ending_with_a_word_character' );