PluginProbe
JetFormBuilder — Dynamic Blocks Form Builder / 3.6.0.1
JetFormBuilder — Dynamic Blocks Form Builder v3.6.0.1
3.6.6.1 3.6.6 3.6.5.4 3.6.5.3 3.6.5.2 3.6.5.1 3.6.5 3.6.4.2 3.6.4.1 3.6.4 3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 All 134 releases
jetformbuilder / modules / block-parsers / field-data-parser.php

field-data-parser.php in JetFormBuilder — Dynamic Blocks Form Builder 3.6.0.1, at modules/block-parsers/field-data-parser.php

600 lines 12.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3
4 namespace JFB_Modules\Block_Parsers;
5
6 use Jet_Form_Builder\Classes\Arrayable\Array_Tools;
7 use Jet_Form_Builder\Classes\Resources\Media_Block_Value;
8 use Jet_Form_Builder\Classes\Resources\Uploaded_File_Path;
9 use Jet_Form_Builder\Classes\Tools;
10 use Jet_Form_Builder\Exceptions\Parse_Exception;
11 use Jet_Form_Builder\Exceptions\Repository_Exception;
12 use Jet_Form_Builder\Request\Exceptions\Plain_Value_Exception;
13 use Jet_Form_Builder\Request\Parser_Context;
14 use JFB_Components\Repository\Repository_Item_Instance_Trait;
15 use Jet_Form_Builder\Classes\Resources\File;
16 use Jet_Form_Builder\Classes\Resources\File_Collection;
17 use Jet_Form_Builder\Request\Exceptions\Exclude_Field_Exception;
18
19 // If this file is called directly, abort.
20 if ( ! defined( 'WPINC' ) ) {
21 die;
22 }
23
24 /**
25 * @property bool is_required
26 *
27 * Class Field_Data_Parser
28 * @package Jet_Form_Builder\Request
29 */
30 abstract class Field_Data_Parser implements Repository_Item_Instance_Trait {
31
32 /**
33 * @var string
34 */
35 protected $name;
36 /**
37 * @var string
38 */
39 protected $type;
40 /**
41 * @var array
42 */
43 protected $settings = array();
44
45 protected $value;
46
47 /** @var File|File_Collection|bool */
48 protected $file;
49
50 /** @var Parser_Context */
51 protected $context;
52
53 /** @var Parser_Context[] */
54 public $inner_contexts;
55
56 /** @var Parser_Context */
57 protected $inner_template;
58
59 protected $with_inner = true;
60
61 /**
62 * @var \WP_Error
63 */
64 protected $wp_error;
65
66 /**
67 * @since 3.3.0
68 * @var bool
69 */
70 private $complete_apply = false;
71
72 /**
73 * Second part in blockName (after "jet-forms/")
74 *
75 * Or return "default" to replace the default parser that applies
76 * to all fields that do not have a personal parser
77 *
78 * @return string
79 */
80 abstract public function type();
81
82 /**
83 * @return string
84 */
85 public function rep_item_id() {
86 return $this->type();
87 }
88
89 /**
90 * Used for internal purposes. To get the true value, use the method
91 * \JFB_Modules\Block_Parsers\Field_Data_Parser::get_value
92 *
93 * @return mixed
94 */
95 public function get_response() {
96 return $this->value;
97 }
98
99 public function update_request() {
100 if ( $this->is_complete_apply() ) {
101 return;
102 }
103
104 $this->wp_error = new \WP_Error();
105
106 try {
107 $this->is_field_visible();
108 $this->set_request();
109 } catch ( Exclude_Field_Exception $exception ) {
110 $this->get_context()->remove( $this->get_name() );
111
112 return;
113 } catch ( Parse_Exception $exception ) {
114 $this->get_context()->remove( $this->get_name() );
115
116 foreach ( $exception->get_inner() as $key => $value ) {
117 $this->get_context()->update_request( $value, $key );
118 }
119
120 return;
121 }
122
123 $this->check_response();
124
125 /**
126 * To prevent repeatable execution of this method
127 *
128 * @since 3.3.0
129 */
130 $this->set_complete_apply( true );
131
132 do_action( 'jet-form-builder/validate-field', $this );
133 }
134
135 /**
136 * @throws Exclude_Field_Exception|Parse_Exception
137 */
138 final public function set_request() {
139 // reset
140 $this->inner_contexts = array();
141
142 $this->set_value( $this->get_context()->get_request( $this->name ) );
143 $this->set_file( $this->get_context()->get_files( $this->name ) );
144
145 $this->value = $this->get_response();
146 }
147
148 public function parse_value( $value ) {
149 return $value;
150 }
151
152 public function check_response() {
153 if (
154 $this->is_inside_conditional() ||
155 ( Tools::is_empty( $this->value ) && ! $this->is_required ) ||
156 ! Tools::is_empty( $this->value )
157 ) {
158 return;
159 }
160
161 $this->collect_error( 'empty_field' );
162 }
163
164 /**
165 * @throws Exclude_Field_Exception
166 */
167 protected function is_field_visible() {
168 $visibility = $this->settings['visibility'] ?? true;
169
170 // If is visible for logged in users and user is logged in - show field.
171 if ( 'logged_id' === $visibility && ! is_user_logged_in() ) {
172 throw new Exclude_Field_Exception();
173 }
174
175 // If is visible for not logged in users and user is not logged in - show field.
176 if ( 'not_logged_in' === $visibility && is_user_logged_in() ) {
177 throw new Exclude_Field_Exception();
178 }
179 }
180
181 public function set_context( Parser_Context $context ): Field_Data_Parser {
182 $this->context = $context;
183
184 return $this;
185 }
186
187 public function set_value( $value ) {
188 $this->value = $this->parse_value( $value );
189 }
190
191 /**
192 * @param bool|Media_Block_Value|Uploaded_File_Path $file
193 */
194 public function set_file( $file ) {
195 $this->file = $file;
196 }
197
198 public function set_type( string $type ) {
199 $this->type = $type;
200 }
201
202 /**
203 * @param string $name
204 */
205 public function set_name( string $name ) {
206 $this->name = $name;
207 }
208
209 /**
210 * @param array $settings
211 *
212 * @since 3.1.0
213 */
214 public function set_settings( array $settings ) {
215 $this->settings = $settings;
216 }
217
218 public function is_secure(): bool {
219 return 'password' === $this->get_setting( 'field_type' );
220 }
221
222 public function make_secure() {
223 $this->set_setting( 'field_type', 'password' );
224 }
225
226 /**
227 * @param string $attr
228 * @param $value
229 *
230 * @since 3.1.0
231 */
232 public function set_setting( string $attr, $value ) {
233 $this->settings[ $attr ] = $value;
234 }
235
236 /**
237 * @return Parser_Context
238 * @since 3.0.4
239 */
240 public function get_context(): Parser_Context {
241 return $this->context;
242 }
243
244 public function iterate_file(): \Generator {
245 yield $this->name => $this->get_file();
246 }
247
248 /**
249 * @return bool|File|File_Collection|array
250 */
251 public function get_file() {
252 if ( empty( $this->inner_contexts ) ) {
253 return $this->file;
254 }
255
256 return iterator_to_array( $this->iterate_inner_files() );
257 }
258
259 public function iterate_self( bool $break_on_first = true ): \Generator {
260 yield $this->get_scoped_name() => $this;
261
262 if ( empty( $this->inner_contexts ) && empty( $this->get_inner_template() ) ) {
263 return;
264 }
265
266 if ( empty( $this->inner_contexts ) ) {
267 yield from $this->get_inner_template()->iterate_parsers_list( $break_on_first );
268
269 return;
270 }
271
272 foreach ( $this->inner_contexts as $context ) {
273 yield from $context->iterate_parsers_list( $break_on_first );
274
275 if ( $break_on_first ) {
276 break;
277 }
278 }
279 }
280
281 /**
282 * @return string
283 */
284 public function get_type(): string {
285 return $this->type;
286 }
287
288 /**
289 * @return string
290 */
291 public function get_name(): string {
292 return $this->name;
293 }
294
295 public function iterate_value(): \Generator {
296 yield $this->name => $this->get_value();
297 }
298
299 public function iterate_row_value(): \Generator {
300 if ( ! $this->get_inner_template() ) {
301 yield $this->get_scoped_name() => $this->get_value();
302
303 return;
304 }
305
306 if ( empty( $this->inner_contexts ) ) {
307 return;
308 }
309
310 $inner = current( $this->inner_contexts );
311
312 if ( ! $inner ) {
313 $inner = end( $this->inner_contexts );
314
315 // current() should always return false, if it has reached end once
316 next( $this->inner_contexts );
317 }
318
319 yield from $inner->iterate_values_row();
320 }
321
322 public function is_inner_over(): bool {
323 return empty( $this->inner_contexts ) || key( $this->inner_contexts ) === null;
324 }
325
326 public function next_inner() {
327 if ( empty( $this->inner_contexts ) ) {
328 return;
329 }
330 next( $this->inner_contexts );
331 }
332
333 /**
334 * @return mixed
335 */
336 public function get_value() {
337 if ( empty( $this->inner_contexts ) || ! $this->with_inner ) {
338 return $this->value;
339 }
340
341 return iterator_to_array( $this->iterate_inner_values() );
342 }
343
344 public function reset() {
345 $this->value = null;
346 $this->file = null;
347 $this->inner_contexts = null;
348 }
349
350 public function get_setting( string $attr_name ) {
351 return $this->settings[ $attr_name ] ?? false;
352 }
353
354 /**
355 * @return array
356 */
357 public function get_settings(): array {
358 return $this->settings;
359 }
360
361 public function __get( $name ) {
362 switch ( $name ) {
363 case 'is_required':
364 return $this->settings['required'] ?? false;
365 default:
366 return null;
367 }
368 }
369
370 /**
371 * @param string|int $index
372 */
373 public function remove_context( $index ) {
374 if ( ! array_key_exists( $index, $this->inner_contexts ) ||
375 ! ( $this->inner_contexts[ $index ] instanceof Parser_Context )
376 ) {
377 return;
378 }
379
380 unset( $this->inner_contexts[ $index ] );
381 }
382
383 public function add_inner( Parser_Context $context, $key = '' ) {
384 if ( '' === $key ) {
385 $this->inner_contexts[] = $context;
386 } else {
387 $this->inner_contexts[ $key ] = $context;
388 }
389
390 return Array_Tools::last_key( $this->inner_contexts );
391 }
392
393 /**
394 * @return Parser_Context|null
395 */
396 public function get_inner_template() {
397 return $this->inner_template;
398 }
399
400 /**
401 * @param Parser_Context $inner_template
402 */
403 public function set_inner_template( Parser_Context $inner_template ) {
404 $this->inner_template = $inner_template;
405 }
406
407 protected function iterate_inner_values(): \Generator {
408 foreach ( $this->inner_contexts as $index => $parser_context ) {
409 yield $index => $parser_context->get_value( array() );
410 }
411 }
412
413 protected function iterate_inner_files(): \Generator {
414 foreach ( $this->inner_contexts as $index => $parser_context ) {
415 yield $index => $parser_context->get_file( array() );
416 }
417 }
418
419 /**
420 * @param array $inner_blocks
421 */
422 public function set_inner_contexts( array $inner_blocks ) {
423 if ( empty( $inner_blocks ) ) {
424 return;
425 }
426
427 $context = new Parser_Context();
428 $context->set_parent( $this );
429 $context->set_parsers( $inner_blocks );
430
431 if ( ! count( iterator_to_array( $context->iterate_parsers() ) ) ) {
432 return;
433 }
434
435 $this->set_inner_template( $context );
436 }
437
438 /**
439 * This applies to the case where the parser is inside a repeater string template.
440 * The difference between the template and the actual context is that the template
441 * cannot contain fields with values, so there is nothing to sanitize there
442 *
443 * @return bool
444 * @since 3.2.0
445 */
446 public function is_in_template(): bool {
447 if ( ! $this->get_context()->get_parent_field() ) {
448 return false;
449 }
450
451 return '' === $this->get_context()->get_index_in_parent();
452 }
453
454 public function get_scoped_name(): string {
455 return trim( $this->get_context()->get_parent_name() . '.' . $this->get_name(), '.' );
456 }
457
458 public function get_scoped_label(): string {
459 return trim( $this->get_context()->get_parent_label() . ':' . $this->get_label(), ':' );
460 }
461
462 public function get_label(): string {
463 $label = $this->settings['label'] ?? '';
464
465 return empty( $label ) ? $this->get_name() : $label;
466 }
467
468 /**
469 * @param bool $with_inner
470 */
471 public function set_with_inner( bool $with_inner ) {
472 $this->with_inner = $with_inner;
473 }
474
475 public function iterate_inner(): \Generator {
476 if ( empty( $this->inner_contexts ) ) {
477 return;
478 }
479
480 foreach ( $this->inner_contexts as $context ) {
481 yield $context;
482 }
483 }
484
485 /**
486 * @param string|\WP_Error $error
487 */
488 public function collect_error( $error, $message = '', $data = '' ) {
489 if ( ! is_wp_error( $this->wp_error ) ) {
490 $this->wp_error = new \WP_Error();
491 }
492
493 if ( is_string( $error ) ) {
494 $this->wp_error->add( $error, $message, $data );
495 }
496 if ( is_wp_error( $error ) ) {
497 $this->wp_error->merge_from( $error );
498 }
499 }
500
501 public function is_collected_error( string $error_code ): bool {
502 if ( ! is_wp_error( $this->wp_error ) ) {
503 return false;
504 }
505 $codes = $this->wp_error->get_error_codes();
506
507 return in_array( $error_code, $codes, true );
508 }
509
510 public function get_errors(): array {
511 return is_wp_error( $this->wp_error ) ? $this->wp_error->get_error_codes() : array();
512 }
513
514 public function set_inside_conditional( bool $is_inside ) {
515 $this->set_setting( '_inside_conditional', $is_inside );
516 }
517
518 public function is_inside_conditional(): bool {
519 return (bool) $this->get_setting( '_inside_conditional' );
520 }
521
522 /**
523 * @param array $path
524 *
525 * @return Field_Data_Parser|Parser_Context
526 * @throws Plain_Value_Exception|Repository_Exception
527 */
528 public function resolve( array $path ) {
529 if ( empty( $this->inner_contexts ) ) {
530 throw new Repository_Exception();
531 }
532
533 $index = array_shift( $path );
534
535 if ( ! array_key_exists( $index, $this->inner_contexts ) ||
536 ! ( $this->inner_contexts[ $index ] instanceof Parser_Context )
537 ) {
538 throw new Repository_Exception();
539 }
540
541 return empty( $path )
542 ? $this->inner_contexts[ $index ]
543 : $this->inner_contexts[ $index ]->resolve( $path );
544 }
545
546 /**
547 * @param string $name
548 *
549 * @return Field_Data_Parser
550 * @throws Plain_Value_Exception|Repository_Exception
551 */
552 public function resolve_to_up( string $name ): Field_Data_Parser {
553 $parser = $this->get_context()->resolve_to_up( $name );
554
555 if ( ! ( $parser instanceof Field_Data_Parser ) ) {
556 throw new Repository_Exception();
557 }
558
559 return $parser;
560 }
561
562 /**
563 * @return bool
564 */
565 public function is_complete_apply(): bool {
566 return $this->complete_apply;
567 }
568
569 /**
570 * @param bool $complete_apply
571 */
572 public function set_complete_apply( bool $complete_apply ) {
573 $this->complete_apply = $complete_apply;
574 }
575
576 public function __clone() {
577 if ( is_array( $this->inner_contexts ) ) {
578 foreach ( $this->inner_contexts as $key => $context ) {
579 $this->inner_contexts[ $key ] = clone $context;
580 }
581 }
582
583 if ( ! is_wp_error( $this->wp_error ) ) {
584 return;
585 }
586
587 $this->wp_error = clone $this->wp_error;
588 }
589
590 public function __debugInfo(): array {
591 $current = clone $this;
592
593 unset( $current->context );
594 $current->wp_error = $current->get_errors();
595
596 return get_object_vars( $current );
597 }
598
599 }
600