type(); } /** * Used for internal purposes. To get the true value, use the method * \JFB_Modules\Block_Parsers\Field_Data_Parser::get_value * * @return mixed */ public function get_response() { return $this->value; } public function update_request() { if ( $this->is_complete_apply() ) { return; } $this->wp_error = new \WP_Error(); try { $this->is_field_visible(); $this->set_request(); } catch ( Exclude_Field_Exception $exception ) { $this->get_context()->remove( $this->get_name() ); return; } catch ( Parse_Exception $exception ) { $this->get_context()->remove( $this->get_name() ); foreach ( $exception->get_inner() as $key => $value ) { $this->get_context()->update_request( $value, $key ); } return; } $this->check_response(); /** * To prevent repeatable execution of this method * * @since 3.3.0 */ $this->set_complete_apply( true ); do_action( 'jet-form-builder/validate-field', $this ); } /** * @throws Exclude_Field_Exception|Parse_Exception */ final public function set_request() { // reset $this->inner_contexts = array(); $this->set_value( $this->get_context()->get_request( $this->name ) ); $this->set_file( $this->get_context()->get_files( $this->name ) ); $this->value = $this->get_response(); } public function parse_value( $value ) { if ( is_array( $value ) && ! $this->allows_array_value() ) { $this->collect_error( 'invalid_value' ); return ''; } return $value; } protected function allows_array_value(): bool { return false; } public function check_response() { if ( $this->is_inside_conditional() || ( Tools::is_empty( $this->value ) && ! $this->is_required ) || ! Tools::is_empty( $this->value ) ) { return; } $this->collect_error( 'empty_field' ); } /** * @throws Exclude_Field_Exception */ protected function is_field_visible() { $visibility = $this->settings['visibility'] ?? true; // If is visible for logged in users and user is logged in - show field. if ( 'logged_id' === $visibility && ! is_user_logged_in() ) { throw new Exclude_Field_Exception(); } // If is visible for not logged in users and user is not logged in - show field. if ( 'not_logged_in' === $visibility && is_user_logged_in() ) { throw new Exclude_Field_Exception(); } } public function set_context( Parser_Context $context ): Field_Data_Parser { $this->context = $context; return $this; } public function set_value( $value ) { $this->value = $this->parse_value( $value ); } /** * @param bool|Media_Block_Value|Uploaded_File_Path $file */ public function set_file( $file ) { $this->file = $file; } public function set_type( string $type ) { $this->type = $type; } /** * @param string $name */ public function set_name( string $name ) { $this->name = $name; } /** * @param array $settings * * @since 3.1.0 */ public function set_settings( array $settings ) { $this->settings = $settings; } public function is_secure(): bool { return 'password' === $this->get_setting( 'field_type' ); } public function make_secure() { $this->set_setting( 'field_type', 'password' ); } /** * @param string $attr * @param $value * * @since 3.1.0 */ public function set_setting( string $attr, $value ) { $this->settings[ $attr ] = $value; } /** * @return Parser_Context * @since 3.0.4 */ public function get_context(): Parser_Context { return $this->context; } public function iterate_file(): \Generator { yield $this->name => $this->get_file(); } /** * @return bool|File|File_Collection|array */ public function get_file() { if ( empty( $this->inner_contexts ) ) { return $this->file; } return iterator_to_array( $this->iterate_inner_files() ); } public function iterate_self( bool $break_on_first = true ): \Generator { yield $this->get_scoped_name() => $this; if ( empty( $this->inner_contexts ) && empty( $this->get_inner_template() ) ) { return; } if ( empty( $this->inner_contexts ) ) { yield from $this->get_inner_template()->iterate_parsers_list( $break_on_first ); return; } foreach ( $this->inner_contexts as $context ) { yield from $context->iterate_parsers_list( $break_on_first ); if ( $break_on_first ) { break; } } } /** * @return string */ public function get_type(): string { return $this->type; } /** * @return string */ public function get_name(): string { return $this->name; } public function iterate_value(): \Generator { yield $this->name => $this->get_value(); } public function iterate_row_value(): \Generator { if ( ! $this->get_inner_template() ) { yield $this->get_scoped_name() => $this->get_value(); return; } if ( empty( $this->inner_contexts ) ) { return; } $inner = current( $this->inner_contexts ); if ( ! $inner ) { $inner = end( $this->inner_contexts ); // current() should always return false, if it has reached end once next( $this->inner_contexts ); } yield from $inner->iterate_values_row(); } public function is_inner_over(): bool { return empty( $this->inner_contexts ) || key( $this->inner_contexts ) === null; } public function next_inner() { if ( empty( $this->inner_contexts ) ) { return; } next( $this->inner_contexts ); } /** * @return mixed */ public function get_value() { if ( empty( $this->inner_contexts ) || ! $this->with_inner ) { return $this->value; } return iterator_to_array( $this->iterate_inner_values() ); } public function reset() { $this->value = null; $this->file = null; $this->inner_contexts = null; } public function get_setting( string $attr_name ) { return $this->settings[ $attr_name ] ?? false; } /** * @return array */ public function get_settings(): array { return $this->settings; } public function __get( $name ) { switch ( $name ) { case 'is_required': return $this->settings['required'] ?? false; default: return null; } } /** * @param string|int $index */ public function remove_context( $index ) { if ( ! array_key_exists( $index, $this->inner_contexts ) || ! ( $this->inner_contexts[ $index ] instanceof Parser_Context ) ) { return; } unset( $this->inner_contexts[ $index ] ); } public function add_inner( Parser_Context $context, $key = '' ) { if ( '' === $key ) { $this->inner_contexts[] = $context; } else { $this->inner_contexts[ $key ] = $context; } return Array_Tools::last_key( $this->inner_contexts ); } /** * @return Parser_Context|null */ public function get_inner_template() { return $this->inner_template; } /** * @param Parser_Context $inner_template */ public function set_inner_template( Parser_Context $inner_template ) { $this->inner_template = $inner_template; } protected function iterate_inner_values(): \Generator { foreach ( $this->inner_contexts as $index => $parser_context ) { yield $index => $parser_context->get_value( array() ); } } protected function iterate_inner_files(): \Generator { foreach ( $this->inner_contexts as $index => $parser_context ) { yield $index => $parser_context->get_file( array() ); } } /** * @param array $inner_blocks */ public function set_inner_contexts( array $inner_blocks ) { if ( empty( $inner_blocks ) ) { return; } $context = new Parser_Context(); $context->set_parent( $this ); $context->set_parsers( $inner_blocks ); if ( ! count( iterator_to_array( $context->iterate_parsers() ) ) ) { return; } $this->set_inner_template( $context ); } /** * This applies to the case where the parser is inside a repeater string template. * The difference between the template and the actual context is that the template * cannot contain fields with values, so there is nothing to sanitize there * * @return bool * @since 3.2.0 */ public function is_in_template(): bool { if ( ! $this->get_context()->get_parent_field() ) { return false; } return '' === $this->get_context()->get_index_in_parent(); } public function get_scoped_name(): string { return trim( $this->get_context()->get_parent_name() . '.' . $this->get_name(), '.' ); } public function get_scoped_label(): string { return trim( $this->get_context()->get_parent_label() . ':' . $this->get_label(), ':' ); } public function get_label(): string { $label = $this->settings['label'] ?? ''; return empty( $label ) ? $this->get_name() : $label; } /** * @param bool $with_inner */ public function set_with_inner( bool $with_inner ) { $this->with_inner = $with_inner; } public function iterate_inner(): \Generator { if ( empty( $this->inner_contexts ) ) { return; } foreach ( $this->inner_contexts as $context ) { yield $context; } } /** * @param string|\WP_Error $error */ public function collect_error( $error, $message = '', $data = '' ) { if ( ! is_wp_error( $this->wp_error ) ) { $this->wp_error = new \WP_Error(); } if ( is_string( $error ) ) { $this->wp_error->add( $error, $message, $data ); } if ( is_wp_error( $error ) ) { $this->wp_error->merge_from( $error ); } } public function is_collected_error( string $error_code ): bool { if ( ! is_wp_error( $this->wp_error ) ) { return false; } $codes = $this->wp_error->get_error_codes(); return in_array( $error_code, $codes, true ); } public function get_errors(): array { return is_wp_error( $this->wp_error ) ? $this->wp_error->get_error_codes() : array(); } public function set_inside_conditional( bool $is_inside ) { $this->set_setting( '_inside_conditional', $is_inside ); } public function is_inside_conditional(): bool { return (bool) $this->get_setting( '_inside_conditional' ); } /** * @param array $path * * @return Field_Data_Parser|Parser_Context * @throws Plain_Value_Exception|Repository_Exception */ public function resolve( array $path ) { if ( empty( $this->inner_contexts ) ) { throw new Repository_Exception(); } $index = array_shift( $path ); if ( ! array_key_exists( $index, $this->inner_contexts ) || ! ( $this->inner_contexts[ $index ] instanceof Parser_Context ) ) { throw new Repository_Exception(); } return empty( $path ) ? $this->inner_contexts[ $index ] : $this->inner_contexts[ $index ]->resolve( $path ); } /** * @param string $name * * @return Field_Data_Parser * @throws Plain_Value_Exception|Repository_Exception */ public function resolve_to_up( string $name ): Field_Data_Parser { $parser = $this->get_context()->resolve_to_up( $name ); if ( ! ( $parser instanceof Field_Data_Parser ) ) { throw new Repository_Exception(); } return $parser; } /** * @return bool */ public function is_complete_apply(): bool { return $this->complete_apply; } /** * @param bool $complete_apply */ public function set_complete_apply( bool $complete_apply ) { $this->complete_apply = $complete_apply; } public function __clone() { if ( is_array( $this->inner_contexts ) ) { foreach ( $this->inner_contexts as $key => $context ) { $this->inner_contexts[ $key ] = clone $context; } } if ( ! is_wp_error( $this->wp_error ) ) { return; } $this->wp_error = clone $this->wp_error; } public function __debugInfo(): array { $current = clone $this; unset( $current->context ); $current->wp_error = $current->get_errors(); return get_object_vars( $current ); } }