PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.8.2
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.8.2
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
formidable / classes / models / FrmEntry.php

FrmEntry.php in Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More 6.8.2, at classes/models/FrmEntry.php

1,110 lines 29.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if ( ! defined( 'ABSPATH' ) ) {
3 die( 'You are not allowed to call this page directly.' );
4 }
5
6 class FrmEntry {
7
8 /**
9 * Create a new entry
10 *
11 * @param array $values
12 *
13 * @return int | boolean $entry_id
14 */
15 public static function create( $values ) {
16 $entry_id = self::create_entry( $values, 'standard' );
17
18 return $entry_id;
19 }
20
21 /**
22 * Create a new entry with some differences depending on type
23 *
24 * @param array $values
25 * @param string $type
26 *
27 * @return int | boolean $entry_id
28 */
29 private static function create_entry( $values, $type ) {
30 $new_values = self::before_insert_entry_in_database( $values, $type );
31
32 // Don't check XML entries for duplicates
33 if ( $type != 'xml' && self::is_duplicate( $new_values, $values ) ) {
34 return false;
35 }
36
37 $entry_id = self::continue_to_create_entry( $values, $new_values );
38
39 return $entry_id;
40 }
41
42 /**
43 * Check for duplicate entries created in the last minute
44 *
45 * @return boolean
46 */
47 public static function is_duplicate( $new_values, $values ) {
48 $duplicate_entry_time = apply_filters( 'frm_time_to_check_duplicates', 60, $new_values );
49
50 if ( false === self::is_duplicate_check_needed( $values, $duplicate_entry_time ) ) {
51 return false;
52 }
53
54 $check_val = $new_values;
55 $check_val['created_at >'] = gmdate( 'Y-m-d H:i:s', ( strtotime( $new_values['created_at'] ) - absint( $duplicate_entry_time ) ) );
56
57 unset( $check_val['created_at'], $check_val['updated_at'], $check_val['is_draft'], $check_val['id'], $check_val['item_key'] );
58
59 if ( $new_values['item_key'] == $new_values['name'] ) {
60 unset( $check_val['name'] );
61 }
62
63 $check_val = apply_filters( 'frm_duplicate_check_val', $check_val );
64
65 global $wpdb;
66 $entry_exists = FrmDb::get_col( $wpdb->prefix . 'frm_items', $check_val, 'id', array( 'order_by' => 'created_at DESC' ) );
67
68 if ( ! $entry_exists || ! isset( $values['item_meta'] ) ) {
69 return false;
70 }
71
72 global $frm_vars;
73 $frm_vars['checking_duplicates'] = true;
74
75 $is_duplicate = false;
76 foreach ( $entry_exists as $entry_exist ) {
77 $is_duplicate = true;
78
79 // make sure it's a duplicate
80 $metas = FrmEntryMeta::get_entry_meta_info( $entry_exist );
81 $field_metas = array();
82 foreach ( $metas as $meta ) {
83 $field_metas[ $meta->field_id ] = $meta->meta_value;
84 }
85
86 $filtered_vals = array_filter( $values['item_meta'] );
87 $filtered_vals = self::convert_values_to_their_saved_value( $filtered_vals, $entry_exist );
88 $field_metas = array_filter( $field_metas );
89
90 // If prev entry is empty and current entry is not, they are not duplicates
91 if ( empty( $field_metas ) && ! empty( $filtered_vals ) ) {
92 return false;
93 }
94
95 // compare serialized values and not arrays
96 $new_meta = array_map( 'maybe_serialize', $filtered_vals );
97
98 if ( $field_metas === $new_meta ) {
99 $is_duplicate = true;
100 break;
101 }
102
103 if ( count( $field_metas ) !== count( $new_meta ) ) {
104 // TODO: compare values saved in the post also
105 $is_duplicate = false;
106 continue;
107 }
108
109 $diff = array_diff_assoc( $field_metas, $new_meta );
110 foreach ( $diff as $field_id => $meta_value ) {
111 if ( ! empty( $meta_value ) ) {
112 $is_duplicate = false;
113 continue;
114 }
115 }
116
117 if ( $is_duplicate ) {
118 break;
119 }
120 }//end foreach
121
122 $frm_vars['checking_duplicates'] = false;
123
124 return $is_duplicate;
125 }
126
127 /**
128 * Convert form data to the actual value that would be saved into the database.
129 * This is important for the duplicate check as something like 'a:2:{s:5:"typed";s:0:"";s:6:"output";s:0:"";}' (a signature value) is actually an empty string and does not get saved.
130 *
131 * @param array $filter_vals
132 * @param int $entry_id
133 * @return array
134 */
135 private static function convert_values_to_their_saved_value( $filter_vals, $entry_id ) {
136 $reduced = array();
137 foreach ( $filter_vals as $field_id => $value ) {
138 $field = FrmFieldFactory::get_field_object( $field_id );
139 $reduced[ $field_id ] = $field->get_value_to_save( $value, array( 'entry_id' => $entry_id ) );
140 $reduced[ $field_id ] = $field->set_value_before_save( $reduced[ $field_id ] );
141 if ( '' === $reduced[ $field_id ] || ( is_array( $reduced[ $field_id ] ) && 0 === count( $reduced[ $field_id ] ) ) ) {
142 unset( $reduced[ $field_id ] );
143 }
144 }
145 return $reduced;
146 }
147
148 /**
149 * Determine if an entry needs to be checked as a possible duplicate
150 *
151 * @since 2.0.23
152 *
153 * @param array $values
154 * @param int $duplicate_entry_time
155 *
156 * @return bool
157 */
158 private static function is_duplicate_check_needed( $values, $duplicate_entry_time ) {
159 // If time for checking duplicates is set to an empty value, don't check for duplicates
160 if ( empty( $duplicate_entry_time ) ) {
161 return false;
162 }
163
164 // If CSV is importing, don't check for duplicates
165 if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
166 return false;
167 }
168
169 // If repeating field entries are getting created, don't check for duplicates
170 if ( isset( $values['parent_form_id'] ) && $values['parent_form_id'] ) {
171 return false;
172 }
173
174 return true;
175 }
176
177 public static function duplicate( $id ) {
178 global $wpdb;
179
180 $values = self::getOne( $id );
181
182 $new_values = array();
183 $new_values['item_key'] = FrmAppHelper::get_unique_key( '', $wpdb->prefix . 'frm_items', 'item_key' );
184 $new_values['name'] = $values->name;
185 $new_values['is_draft'] = $values->is_draft;
186 $new_values['user_id'] = (int) $values->user_id;
187 $new_values['updated_by'] = (int) $values->user_id;
188 $new_values['form_id'] = $values->form_id ? (int) $values->form_id : null;
189 $new_values['created_at'] = current_time( 'mysql', 1 );
190 $new_values['updated_at'] = $new_values['created_at'];
191
192 $query_results = $wpdb->insert( $wpdb->prefix . 'frm_items', $new_values );
193 if ( ! $query_results ) {
194 return false;
195 }
196
197 $entry_id = $wpdb->insert_id;
198
199 global $frm_vars;
200 if ( ! isset( $frm_vars['saved_entries'] ) ) {
201 $frm_vars['saved_entries'] = array();
202 }
203 $frm_vars['saved_entries'][] = (int) $entry_id;
204
205 FrmEntryMeta::duplicate_entry_metas( $id, $entry_id );
206 self::clear_cache();
207
208 do_action( 'frm_after_duplicate_entry', $entry_id, $new_values['form_id'], array( 'old_id' => $id ) );
209
210 return $entry_id;
211 }
212
213 /**
214 * Update an entry (not via XML)
215 *
216 * @param int $id
217 * @param array $values
218 *
219 * @return boolean|int $update_results
220 */
221 public static function update( $id, $values ) {
222 $update_results = self::update_entry( $id, $values, 'standard' );
223
224 return $update_results;
225 }
226
227 /**
228 * Update an entry with some differences depending on the update type
229 *
230 * @since 2.0.16
231 *
232 * @param int $id
233 * @param array $values
234 *
235 * @return boolean|int $query_results
236 */
237 private static function update_entry( $id, $values, $update_type ) {
238 global $wpdb;
239
240 $update = self::before_update_entry( $id, $values, $update_type );
241 if ( ! $update ) {
242 return false;
243 }
244
245 $new_values = self::package_entry_to_update( $id, $values );
246
247 $query_results = $wpdb->update( $wpdb->prefix . 'frm_items', $new_values, compact( 'id' ) );
248
249 self::after_update_entry( $query_results, $id, $values, $new_values );
250
251 return $query_results;
252 }
253
254 /**
255 * Delete an entry.
256 *
257 * @param string|int $id
258 * @return bool True on success, false if nothing was deleted.
259 */
260 public static function destroy( $id ) {
261 global $wpdb;
262 $id = (int) $id;
263
264 // Item meta is required for conditional logic in actions with 'delete' events.
265 $entry = self::getOne( $id, true );
266 if ( ! $entry ) {
267 $result = false;
268 return $result;
269 }
270
271 /**
272 * Trigger an action to run custom logic before the entry is deleted.
273 *
274 * @param int $id The id of the entry that was destroyed.
275 * @param stdClass $entry The entry object.
276 */
277 do_action( 'frm_before_destroy_entry', $id, $entry );
278
279 $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_item_metas WHERE item_id=%d', $id ) );
280 $result = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_items WHERE id=%d', $id ) );
281
282 self::clear_cache();
283
284 /**
285 * Trigger an action to run custom logic after the entry is deleted.
286 * Use this hook if you need to update caching after an entry is deleted.
287 *
288 * @since 5.4.1
289 *
290 * @param int $id The id of the entry that was destroyed.
291 * @param stdClass $entry The entry object.
292 */
293 do_action( 'frm_after_destroy_entry', $id, $entry );
294
295 return $result;
296 }
297
298 public static function update_form( $id, $value, $form_id ) {
299 global $wpdb;
300 $form_id = isset( $value ) ? $form_id : null;
301 $result = $wpdb->update( $wpdb->prefix . 'frm_items', array( 'form_id' => $form_id ), array( 'id' => $id ) );
302 if ( $result ) {
303 self::clear_cache();
304 }
305
306 return $result;
307 }
308
309 /**
310 * Clear entry caching
311 * Called when an entry is changed
312 *
313 * @since 2.0.5
314 */
315 public static function clear_cache() {
316 FrmDb::cache_delete_group( 'frm_entry' );
317 FrmDb::cache_delete_group( 'frm_item' );
318 FrmDb::cache_delete_group( 'frm_entry_meta' );
319 FrmDb::cache_delete_group( 'frm_item_meta' );
320 }
321
322 /**
323 * After switching to the wp_loaded hook for processing entries,
324 * we can no longer use 'name', but check it as a fallback
325 *
326 * @since 2.0.11
327 */
328 public static function get_new_entry_name( $values, $default = '' ) {
329 $name = isset( $values['item_name'] ) ? $values['item_name'] : ( isset( $values['name'] ) ? $values['name'] : $default );
330 if ( is_array( $name ) ) {
331 $name = reset( $name );
332 }
333
334 return $name;
335 }
336
337 /**
338 * If $entry is numeric, get the entry object
339 *
340 * @param int|object $entry By reference.
341 *
342 * @since 2.0.9
343 */
344 public static function maybe_get_entry( &$entry ) {
345 if ( $entry && is_numeric( $entry ) ) {
346 $entry = self::getOne( $entry );
347 } elseif ( empty( $entry ) || 'false' === $entry ) {
348 $entry = false;
349 }
350 }
351
352 public static function getOne( $id, $meta = false ) {
353 global $wpdb;
354
355 $query = "SELECT it.*, fr.name as form_name, fr.form_key as form_key FROM {$wpdb->prefix}frm_items it
356 LEFT OUTER JOIN {$wpdb->prefix}frm_forms fr ON it.form_id=fr.id WHERE ";
357
358 $query .= is_numeric( $id ) ? 'it.id=%d' : 'it.item_key=%s';
359 $query_args = array( $id );
360 $query = $wpdb->prepare( $query, $query_args ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
361
362 if ( ! $meta ) {
363 $entry = FrmDb::check_cache( $id . '_nometa', 'frm_entry', $query, 'get_row' );
364 self::prepare_entry( $entry );
365 return $entry;
366 }
367
368 $entry = FrmDb::check_cache( $id, 'frm_entry' );
369 if ( $entry !== false ) {
370 self::prepare_entry( $entry );
371 return $entry;
372 }
373
374 $entry = $wpdb->get_row( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
375 $entry = self::get_meta( $entry );
376 self::prepare_entry( $entry );
377
378 return $entry;
379 }
380
381 /**
382 * @since 4.02.03
383 *
384 * @param object $entry
385 */
386 private static function prepare_entry( &$entry ) {
387 if ( empty( $entry ) ) {
388 return;
389 }
390
391 FrmAppHelper::unserialize_or_decode( $entry->description );
392 // TODO: Remove slashes on input only, not output.
393 $entry = wp_unslash( $entry );
394 }
395
396 /**
397 * @since 4.02.03
398 *
399 * @param array $entries
400 */
401 private static function prepare_entries( &$entries ) {
402 foreach ( $entries as $k => $entry ) {
403 self::prepare_entry( $entry );
404 $entries[ $k ] = $entry;
405 }
406 }
407
408 public static function get_meta( $entry ) {
409 if ( ! $entry ) {
410 return $entry;
411 }
412
413 global $wpdb;
414 $metas = FrmDb::get_results(
415 $wpdb->prefix . 'frm_item_metas m LEFT JOIN ' . $wpdb->prefix . 'frm_fields f ON m.field_id=f.id',
416 array(
417 'item_id' => $entry->id,
418 'field_id !' => 0,
419 ),
420 'field_id, meta_value, field_key, item_id, f.type'
421 );
422
423 $entry->metas = array();
424
425 $include_key = apply_filters( 'frm_include_meta_keys', false, array( 'form_id' => $entry->form_id ) );
426 foreach ( $metas as $meta_val ) {
427 FrmFieldsHelper::prepare_field_value( $meta_val->meta_value, $meta_val->type );
428
429 if ( $meta_val->item_id == $entry->id ) {
430 $entry->metas[ $meta_val->field_id ] = $meta_val->meta_value;
431 if ( $include_key ) {
432 $entry->metas[ $meta_val->field_key ] = $entry->metas[ $meta_val->field_id ];
433 }
434 continue;
435 }
436
437 // include sub entries in an array
438 if ( ! isset( $entry->metas[ $meta_val->field_id ] ) ) {
439 $entry->metas[ $meta_val->field_id ] = array();
440 }
441
442 $entry->metas[ $meta_val->field_id ][] = $meta_val->meta_value;
443
444 unset( $meta_val );
445 }
446 unset( $metas );
447
448 FrmDb::set_cache( $entry->id, $entry, 'frm_entry' );
449
450 return $entry;
451 }
452
453 /**
454 * @param string $id
455 */
456 public static function exists( $id ) {
457 global $wpdb;
458
459 if ( FrmDb::check_cache( $id, 'frm_entry' ) ) {
460 $exists = true;
461
462 return $exists;
463 }
464
465 if ( is_numeric( $id ) ) {
466 $where = array( 'id' => $id );
467 } else {
468 $where = array( 'item_key' => $id );
469 }
470 $id = FrmDb::get_var( $wpdb->prefix . 'frm_items', $where );
471
472 return ( $id && $id > 0 );
473 }
474
475 public static function getAll( $where, $order_by = '', $limit = '', $meta = false, $inc_form = true ) {
476 global $wpdb;
477
478 $limit = FrmDb::esc_limit( $limit );
479
480 $cache_key = FrmAppHelper::maybe_json_encode( $where ) . $order_by . $limit . $inc_form;
481 $entries = wp_cache_get( $cache_key, 'frm_entry' );
482
483 if ( false === $entries ) {
484 $fields = 'it.id, it.item_key, it.name, it.ip, it.form_id, it.post_id, it.user_id, it.parent_item_id, it.updated_by, it.created_at, it.updated_at, it.is_draft, it.description';
485 $table = $wpdb->prefix . 'frm_items it ';
486
487 if ( $inc_form ) {
488 $fields = 'it.*, fr.name as form_name,fr.form_key as form_key';
489 $table .= 'LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_forms fr ON it.form_id=fr.id ';
490 }
491
492 if ( preg_match( '/ meta_([0-9]+)/', $order_by, $order_matches ) ) {
493 $fields .= self::sort_by_field( $order_matches[1] );
494 unset( $order_matches );
495 }
496
497 // prepare the query
498 $query = 'SELECT ' . $fields . ' FROM ' . $table . FrmDb::prepend_and_or_where( ' WHERE ', $where ) . $order_by . $limit;
499
500 $entries = $wpdb->get_results( $query, OBJECT_K ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
501 unset( $query );
502
503 FrmDb::set_cache( $cache_key, $entries, 'frm_entry' );
504 }//end if
505
506 if ( ! $meta || ! $entries ) {
507 self::prepare_entries( $entries );
508 return $entries;
509 }
510 unset( $meta );
511
512 if ( ! is_array( $where ) && preg_match( '/^it\.form_id=\d+$/', $where ) ) {
513 $where = array( 'it.form_id' => substr( $where, 11 ) );
514 }
515
516 $meta_where = array( 'field_id !' => 0 );
517 if ( $limit == '' && is_array( $where ) && count( $where ) == 1 && isset( $where['it.form_id'] ) ) {
518 $meta_where['fi.form_id'] = $where['it.form_id'];
519 } else {
520 $meta_where['item_id'] = array_keys( $entries );
521 }
522
523 $metas = FrmDb::get_results(
524 $wpdb->prefix . 'frm_item_metas it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_fields fi ON it.field_id = fi.id',
525 $meta_where,
526 'item_id, meta_value, field_id, field_key, form_id, fi.type'
527 );
528
529 unset( $meta_where );
530
531 if ( ! $metas ) {
532 self::prepare_entries( $entries );
533 return $entries;
534 }
535
536 foreach ( $metas as $m_key => $meta_val ) {
537 if ( ! isset( $entries[ $meta_val->item_id ] ) ) {
538 continue;
539 }
540
541 if ( ! isset( $entries[ $meta_val->item_id ]->metas ) ) {
542 $entries[ $meta_val->item_id ]->metas = array();
543 }
544
545 FrmFieldsHelper::prepare_field_value( $meta_val->meta_value, $meta_val->type );
546 $entries[ $meta_val->item_id ]->metas[ $meta_val->field_id ] = $meta_val->meta_value;
547 unset( $m_key, $meta_val );
548 }
549
550 if ( ! FrmAppHelper::prevent_caching() ) {
551 foreach ( $entries as $entry ) {
552 FrmDb::set_cache( $entry->id, $entry, 'frm_entry' );
553 unset( $entry );
554 }
555 }
556
557 self::prepare_entries( $entries );
558 return $entries;
559 }
560
561 /**
562 * @param int $field_id
563 * @return string
564 */
565 private static function sort_by_field( $field_id ) {
566 global $wpdb;
567 $field_id = (int) $field_id;
568
569 $field_options = FrmDb::get_var( 'frm_fields', array( 'id' => $field_id ), 'field_options' );
570 FrmAppHelper::unserialize_or_decode( $field_options );
571
572 if ( empty( $field_options['post_field'] ) ) {
573 $sort = ', (SELECT meta_value FROM ' . $wpdb->prefix . 'frm_item_metas WHERE field_id = ' . $field_id . ' AND item_id = it.id) as meta_' . $field_id;
574 } else {
575 $sort = '';
576 }
577
578 return apply_filters( 'frm_handle_field_column_sort', $sort, $field_id, $field_options );
579 }
580
581 // Pagination Methods
582 /**
583 * @param int|array|string $where If int, use the form id.
584 */
585 public static function getRecordCount( $where = '' ) {
586 global $wpdb;
587 $table_join = $wpdb->prefix . 'frm_items it JOIN ' . $wpdb->prefix . 'frm_forms fr ON it.form_id=fr.id';
588
589 if ( is_numeric( $where ) ) {
590 $table_join = 'frm_items';
591 $where = array( 'form_id' => $where );
592 }
593
594 if ( is_array( $where ) ) {
595 $count = FrmDb::get_count( $table_join, $where );
596 } else {
597 $cache_key = 'count_' . FrmAppHelper::maybe_json_encode( $where );
598 $query = 'SELECT COUNT(*) FROM ' . $table_join . FrmDb::prepend_and_or_where( ' WHERE ', $where );
599 $count = FrmDb::check_cache( $cache_key, 'frm_entry', $query, 'get_var' );
600 }
601
602 return $count;
603 }
604
605 public static function getPageCount( $p_size, $where = '' ) {
606 $p_size = (int) $p_size;
607 $count = 1;
608 if ( $p_size ) {
609 if ( ! is_numeric( $where ) ) {
610 $where = self::getRecordCount( $where );
611 }
612 $count = ceil( (int) $where / $p_size );
613 }
614
615 return $count;
616 }
617
618 /**
619 * Prepare the data before inserting it into the database
620 *
621 * @since 2.0.16
622 *
623 * @param array $values
624 * @param string $type
625 *
626 * @return array $new_values
627 */
628 private static function before_insert_entry_in_database( &$values, $type ) {
629
630 self::sanitize_entry_post( $values );
631
632 if ( $type != 'xml' ) {
633 $values = apply_filters( 'frm_pre_create_entry', $values );
634 }
635
636 $new_values = self::package_entry_data( $values );
637
638 return $new_values;
639 }
640
641 /**
642 * Create an entry and perform after create actions
643 *
644 * @since 2.0.16
645 *
646 * @param array $values
647 * @param array $new_values
648 *
649 * @return boolean|int $entry_id
650 */
651 private static function continue_to_create_entry( $values, $new_values ) {
652 $entry_id = self::insert_entry_into_database( $new_values );
653 if ( ! $entry_id ) {
654 return false;
655 }
656
657 self::after_insert_entry_in_database( $values, $new_values, $entry_id );
658
659 return $entry_id;
660 }
661
662 /**
663 * Sanitize the POST values before we use them
664 *
665 * @since 2.0
666 *
667 * @param array $values The POST values by reference.
668 */
669 public static function sanitize_entry_post( &$values ) {
670 $sanitize_method = array(
671 'form_id' => 'absint',
672 'frm_action' => 'sanitize_title',
673 'form_key' => 'sanitize_title',
674 'item_key' => 'sanitize_title',
675 'item_name' => 'sanitize_text_field',
676 'frm_saving_draft' => 'absint',
677 'is_draft' => 'absint',
678 'post_id' => 'absint',
679 'parent_item_id' => 'absint',
680 'created_at' => 'sanitize_text_field',
681 'updated_at' => 'sanitize_text_field',
682 );
683
684 FrmAppHelper::sanitize_request( $sanitize_method, $values );
685 }
686
687 /**
688 * Prepare the new values for inserting into the database
689 *
690 * @since 2.0.16
691 *
692 * @param array $values
693 *
694 * @return array $new_values
695 */
696 private static function package_entry_data( &$values ) {
697 global $wpdb;
698
699 if ( ! isset( $values['item_key'] ) ) {
700 $values['item_key'] = '';
701 }
702
703 $item_name = self::get_new_entry_name( $values, $values['item_key'] );
704 $new_values = array(
705 'item_key' => FrmAppHelper::get_unique_key( $values['item_key'], $wpdb->prefix . 'frm_items', 'item_key' ),
706 'name' => FrmAppHelper::truncate( $item_name, 255, 1, '' ),
707 'ip' => self::get_ip( $values ),
708 'is_draft' => self::get_is_draft_value( $values ),
709 'form_id' => (int) self::get_entry_value( $values, 'form_id', null ),
710 'post_id' => (int) self::get_entry_value( $values, 'post_id', 0 ),
711 'parent_item_id' => (int) self::get_entry_value( $values, 'parent_item_id', 0 ),
712 'created_at' => self::get_created_at( $values ),
713 'updated_at' => self::get_updated_at( $values ),
714 'description' => self::get_entry_description( $values ),
715 'user_id' => self::get_entry_user_id( $values ),
716 );
717
718 $new_values['updated_by'] = isset( $values['updated_by'] ) ? $values['updated_by'] : $new_values['user_id'];
719
720 return $new_values;
721 }
722
723 private static function get_entry_value( $values, $name, $default ) {
724 return isset( $values[ $name ] ) ? $values[ $name ] : $default;
725 }
726
727 /**
728 * Get the ip for a new entry.
729 * Allow the import to override the value.
730 *
731 * @since 2.03.10
732 *
733 * @param array $values
734 *
735 * @return string
736 */
737 private static function get_ip( $values ) {
738 if ( ! FrmAppHelper::ips_saved() ) {
739 return '';
740 }
741
742 $ip = FrmAppHelper::get_ip_address();
743 if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
744 $ip = self::get_entry_value( $values, 'ip', $ip );
745 }
746
747 return $ip;
748 }
749
750 /**
751 * Get the is_draft value for a new entry
752 *
753 * @since 2.0.16
754 *
755 * @param array $values
756 *
757 * @return int
758 */
759 private static function get_is_draft_value( $values ) {
760 if ( isset( $values['frm_saving_draft'] ) && FrmEntriesHelper::DRAFT_ENTRY_STATUS === (int) $values['frm_saving_draft'] ) {
761 return FrmEntriesHelper::DRAFT_ENTRY_STATUS;
762 }
763
764 return isset( $values['is_draft'] ) ? absint( $values['is_draft'] ) : FrmEntriesHelper::SUBMITTED_ENTRY_STATUS;
765 }
766
767 /**
768 * Get the created_at value for a new entry
769 *
770 * @since 2.0.16
771 *
772 * @param array $values
773 *
774 * @return string
775 */
776 private static function get_created_at( $values ) {
777 return self::get_entry_value( $values, 'created_at', current_time( 'mysql', 1 ) );
778 }
779
780 /**
781 * Get the updated_at value for a new entry
782 *
783 * @since 2.0.16
784 *
785 * @param array $values
786 *
787 * @return string
788 */
789 private static function get_updated_at( $values ) {
790 if ( isset( $values['updated_at'] ) ) {
791 $updated_at = $values['updated_at'];
792 } else {
793 $updated_at = self::get_created_at( $values );
794 }
795
796 return $updated_at;
797 }
798
799 /**
800 * Get the description value for a new entry
801 *
802 * @since 2.0.16
803 *
804 * @param array $values
805 *
806 * @return string
807 */
808 private static function get_entry_description( $values ) {
809 if ( isset( $values['description'] ) && ! empty( $values['description'] ) ) {
810 $description = FrmAppHelper::maybe_json_encode( $values['description'] );
811 } else {
812 $description = json_encode(
813 array(
814 'browser' => FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' ),
815 'referrer' => FrmAppHelper::get_server_value( 'HTTP_REFERER' ),
816 )
817 );
818 }
819
820 return $description;
821 }
822
823 /**
824 * Get the user_id value for a new entry
825 *
826 * @since 2.0.16
827 *
828 * @param array $values
829 *
830 * @return int
831 */
832 private static function get_entry_user_id( $values ) {
833 if ( isset( $values['frm_user_id'] ) && ( is_numeric( $values['frm_user_id'] ) || FrmAppHelper::is_admin() ) ) {
834 $user_id = $values['frm_user_id'];
835 } else {
836 $current_user_id = get_current_user_id();
837 $user_id = $current_user_id ? $current_user_id : 0;
838 }
839
840 return $user_id;
841 }
842
843 /**
844 * Insert new entry into the database
845 *
846 * @since 2.0.16
847 *
848 * @param array $new_values
849 *
850 * @return int | boolean $entry_id
851 */
852 private static function insert_entry_into_database( $new_values ) {
853 global $wpdb;
854
855 $query_results = $wpdb->insert( $wpdb->prefix . 'frm_items', $new_values );
856
857 if ( ! $query_results ) {
858 $entry_id = false;
859 } else {
860 $entry_id = $wpdb->insert_id;
861 }
862
863 return $entry_id;
864 }
865
866 /**
867 * Add the new entry to global $frm_vars
868 *
869 * @since 2.0.16
870 *
871 * @param int $entry_id
872 */
873 private static function add_new_entry_to_frm_vars( $entry_id ) {
874 global $frm_vars;
875
876 if ( ! isset( $frm_vars['saved_entries'] ) ) {
877 $frm_vars['saved_entries'] = array();
878 }
879
880 $frm_vars['saved_entries'][] = (int) $entry_id;
881 }
882
883 /**
884 * Add entry metas, if there are any
885 *
886 * @since 2.0.16
887 *
888 * @param array $values
889 * @param int $entry_id
890 * @return void
891 */
892 private static function maybe_add_entry_metas( $values, $entry_id ) {
893 if ( isset( $values['item_meta'] ) ) {
894 FrmEntryMeta::update_entry_metas( $entry_id, $values['item_meta'] );
895 }
896 self::maybe_add_captcha_meta( (int) $values['form_id'], (int) $entry_id );
897 }
898
899 /**
900 * @since 5.0.15
901 *
902 * @param int $form_id
903 * @param int $entry_id
904 * @return void
905 */
906 private static function maybe_add_captcha_meta( $form_id, $entry_id ) {
907 global $frm_vars;
908 if ( array_key_exists( 'captcha_scores', $frm_vars ) && array_key_exists( $form_id, $frm_vars['captcha_scores'] ) ) {
909 $captcha_score_meta = array( 'captcha_score' => $frm_vars['captcha_scores'][ $form_id ] );
910 FrmEntryMeta::add_entry_meta( $entry_id, 0, '', maybe_serialize( $captcha_score_meta ) );
911 }
912 }
913
914 /**
915 * Trigger frm_after_create_entry hooks
916 *
917 * @since 2.0.16
918 *
919 * @param int $entry_id
920 * @param array $values
921 * @param array $new_values
922 */
923 private static function after_entry_created_actions( $entry_id, $values, $new_values ) {
924 // this is a child entry
925 $is_child = isset( $values['parent_form_id'] ) && isset( $values['parent_nonce'] ) && ! empty( $values['parent_form_id'] ) && wp_verify_nonce( $values['parent_nonce'], 'parent' );
926
927 do_action( 'frm_after_create_entry', $entry_id, $new_values['form_id'], compact( 'is_child' ) );
928 do_action( 'frm_after_create_entry_' . $new_values['form_id'], $entry_id, compact( 'is_child' ) );
929 }
930
931 /**
932 * Actions to perform immediately after an entry is inserted in the frm_items database
933 *
934 * @since 2.0.16
935 *
936 * @param array $values
937 * @param array $new_values
938 * @param int $entry_id
939 */
940 private static function after_insert_entry_in_database( $values, $new_values, $entry_id ) {
941
942 self::add_new_entry_to_frm_vars( $entry_id );
943
944 self::maybe_add_entry_metas( $values, $entry_id );
945
946 self::clear_cache();
947
948 self::after_entry_created_actions( $entry_id, $values, $new_values );
949 }
950
951 /**
952 * Perform some actions right before updating an entry
953 *
954 * @since 2.0.16
955 *
956 * @param int $id
957 * @param array $values
958 * @param string $update_type
959 *
960 * @return boolean $update
961 */
962 private static function before_update_entry( $id, &$values, $update_type ) {
963 $update = true;
964
965 global $frm_vars;
966
967 if ( isset( $frm_vars['saved_entries'] ) && is_array( $frm_vars['saved_entries'] ) && in_array( (int) $id, (array) $frm_vars['saved_entries'] ) ) {
968 $update = false;
969 }
970
971 if ( $update && $update_type != 'xml' ) {
972 $values = apply_filters( 'frm_pre_update_entry', $values, $id );
973 }
974
975 return $update;
976 }
977
978 /**
979 * Package the entry data for updating
980 *
981 * @since 2.0.16
982 *
983 * @param int $id
984 * @param array $values
985 *
986 * @return array $new_values
987 */
988 private static function package_entry_to_update( $id, $values ) {
989 global $wpdb;
990
991 $new_values = array(
992 'name' => self::get_new_entry_name( $values ),
993 'form_id' => (int) self::get_entry_value( $values, 'form_id', null ),
994 'is_draft' => self::get_is_draft_value( $values ),
995 'updated_at' => current_time( 'mysql', 1 ),
996 'updated_by' => isset( $values['updated_by'] ) ? $values['updated_by'] : get_current_user_id(),
997 );
998
999 if ( isset( $values['post_id'] ) ) {
1000 $new_values['post_id'] = (int) $values['post_id'];
1001 }
1002
1003 if ( isset( $values['item_key'] ) ) {
1004 $new_values['item_key'] = FrmAppHelper::get_unique_key( $values['item_key'], $wpdb->prefix . 'frm_items', 'item_key', $id );
1005 }
1006
1007 if ( isset( $values['parent_item_id'] ) ) {
1008 $new_values['parent_item_id'] = (int) $values['parent_item_id'];
1009 }
1010
1011 if ( isset( $values['frm_user_id'] ) && is_numeric( $values['frm_user_id'] ) ) {
1012 $new_values['user_id'] = $values['frm_user_id'];
1013 }
1014
1015 $new_values = apply_filters( 'frm_update_entry', $new_values, $id );
1016
1017 return $new_values;
1018 }
1019
1020 /**
1021 * Perform some actions right after updating an entry
1022 *
1023 * @since 2.0.16
1024 *
1025 * @param boolean|int $query_results
1026 * @param int $id
1027 * @param array $values
1028 * @param array $new_values
1029 */
1030 private static function after_update_entry( $query_results, $id, $values, $new_values ) {
1031 if ( $query_results ) {
1032 self::clear_cache();
1033 }
1034
1035 global $frm_vars;
1036 if ( ! isset( $frm_vars['saved_entries'] ) ) {
1037 $frm_vars['saved_entries'] = array();
1038 }
1039
1040 $frm_vars['saved_entries'][] = (int) $id;
1041
1042 if ( isset( $values['item_meta'] ) ) {
1043 FrmEntryMeta::update_entry_metas( $id, $values['item_meta'] );
1044 }
1045
1046 do_action( 'frm_after_update_entry', $id, $new_values['form_id'] );
1047 do_action( 'frm_after_update_entry_' . $new_values['form_id'], $id );
1048 }
1049
1050 /**
1051 * Create entry from an XML import
1052 * Certain actions aren't necessary when importing (like saving sub entries, checking for duplicates, etc.)
1053 *
1054 * @since 2.0.16
1055 *
1056 * @param array $values
1057 *
1058 * @return int | boolean $entry_id
1059 */
1060 public static function create_entry_from_xml( $values ) {
1061 $entry_id = self::create_entry( $values, 'xml' );
1062
1063 return $entry_id;
1064 }
1065
1066 /**
1067 * Update entry from an XML import
1068 * Certain actions aren't necessary when importing (like saving sub entries and modifying other vals)
1069 *
1070 * @since 2.0.16
1071 *
1072 * @param int $id
1073 * @param array $values
1074 *
1075 * @return int | boolean $updated
1076 */
1077 public static function update_entry_from_xml( $id, $values ) {
1078 $updated = self::update_entry( $id, $values, 'xml' );
1079
1080 return $updated;
1081 }
1082
1083 /**
1084 * @param string $key
1085 *
1086 * @return int entry_id
1087 */
1088 public static function get_id_by_key( $key ) {
1089 $entry_id = FrmDb::get_var( 'frm_items', array( 'item_key' => sanitize_title( $key ) ) );
1090
1091 return (int) $entry_id;
1092 }
1093
1094 /**
1095 * Get entries count.
1096 *
1097 * @since 6.8
1098 *
1099 * @return int
1100 */
1101 public static function get_entries_count() {
1102 $args = array(
1103 'or' => 1,
1104 'parent_form_id' => null,
1105 'parent_form_id <' => 1,
1106 );
1107 return self::getRecordCount( $args );
1108 }
1109 }
1110