PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.4
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.4
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.4, at classes/models/FrmEntry.php

1,087 lines 28.8 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 }
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 $entry = self::getOne( $id, true ); // Item meta is required for conditional logic in actions with 'delete' events.
265 if ( ! $entry ) {
266 $result = false;
267 return $result;
268 }
269
270 /**
271 * Trigger an action to run custom logic before the entry is deleted.
272 *
273 * @param int $id The id of the entry that was destroyed.
274 * @param stdClass $entry The entry object.
275 */
276 do_action( 'frm_before_destroy_entry', $id, $entry );
277
278 $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_item_metas WHERE item_id=%d', $id ) );
279 $result = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_items WHERE id=%d', $id ) );
280
281 self::clear_cache();
282
283 /**
284 * Trigger an action to run custom logic after the entry is deleted.
285 * Use this hook if you need to update caching after an entry is deleted.
286 *
287 * @since 5.4.1
288 *
289 * @param int $id The id of the entry that was destroyed.
290 * @param stdClass $entry The entry object.
291 */
292 do_action( 'frm_after_destroy_entry', $id, $entry );
293
294 return $result;
295 }
296
297 public static function update_form( $id, $value, $form_id ) {
298 global $wpdb;
299 $form_id = isset( $value ) ? $form_id : null;
300 $result = $wpdb->update( $wpdb->prefix . 'frm_items', array( 'form_id' => $form_id ), array( 'id' => $id ) );
301 if ( $result ) {
302 self::clear_cache();
303 }
304
305 return $result;
306 }
307
308 /**
309 * Clear entry caching
310 * Called when an entry is changed
311 *
312 * @since 2.0.5
313 */
314 public static function clear_cache() {
315 FrmDb::cache_delete_group( 'frm_entry' );
316 FrmDb::cache_delete_group( 'frm_item' );
317 FrmDb::cache_delete_group( 'frm_entry_meta' );
318 FrmDb::cache_delete_group( 'frm_item_meta' );
319 }
320
321 /**
322 * After switching to the wp_loaded hook for processing entries,
323 * we can no longer use 'name', but check it as a fallback
324 *
325 * @since 2.0.11
326 */
327 public static function get_new_entry_name( $values, $default = '' ) {
328 $name = isset( $values['item_name'] ) ? $values['item_name'] : ( isset( $values['name'] ) ? $values['name'] : $default );
329 if ( is_array( $name ) ) {
330 $name = reset( $name );
331 }
332
333 return $name;
334 }
335
336 /**
337 * If $entry is numeric, get the entry object
338 *
339 * @param int|object $entry by reference
340 *
341 * @since 2.0.9
342 */
343 public static function maybe_get_entry( &$entry ) {
344 if ( $entry && is_numeric( $entry ) ) {
345 $entry = self::getOne( $entry );
346 } elseif ( empty( $entry ) || 'false' === $entry ) {
347 $entry = false;
348 }
349 }
350
351 public static function getOne( $id, $meta = false ) {
352 global $wpdb;
353
354 $query = "SELECT it.*, fr.name as form_name, fr.form_key as form_key FROM {$wpdb->prefix}frm_items it
355 LEFT OUTER JOIN {$wpdb->prefix}frm_forms fr ON it.form_id=fr.id WHERE ";
356
357 $query .= is_numeric( $id ) ? 'it.id=%d' : 'it.item_key=%s';
358 $query_args = array( $id );
359 $query = $wpdb->prepare( $query, $query_args ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
360
361 if ( ! $meta ) {
362 $entry = FrmDb::check_cache( $id . '_nometa', 'frm_entry', $query, 'get_row' );
363 self::prepare_entry( $entry );
364 return $entry;
365 }
366
367 $entry = FrmDb::check_cache( $id, 'frm_entry' );
368 if ( $entry !== false ) {
369 self::prepare_entry( $entry );
370 return $entry;
371 }
372
373 $entry = $wpdb->get_row( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
374 $entry = self::get_meta( $entry );
375 self::prepare_entry( $entry );
376
377 return $entry;
378 }
379
380 /**
381 * @since 4.02.03
382 *
383 * @param object $entry
384 */
385 private static function prepare_entry( &$entry ) {
386 if ( empty( $entry ) ) {
387 return;
388 }
389
390 FrmAppHelper::unserialize_or_decode( $entry->description );
391 $entry = wp_unslash( $entry ); // TODO: Remove slashes on input only, not output.
392 }
393
394 /**
395 * @since 4.02.03
396 *
397 * @param array $entries
398 */
399 private static function prepare_entries( &$entries ) {
400 foreach ( $entries as $k => $entry ) {
401 self::prepare_entry( $entry );
402 $entries[ $k ] = $entry;
403 }
404 }
405
406 public static function get_meta( $entry ) {
407 if ( ! $entry ) {
408 return $entry;
409 }
410
411 global $wpdb;
412 $metas = FrmDb::get_results(
413 $wpdb->prefix . 'frm_item_metas m LEFT JOIN ' . $wpdb->prefix . 'frm_fields f ON m.field_id=f.id',
414 array(
415 'item_id' => $entry->id,
416 'field_id !' => 0,
417 ),
418 'field_id, meta_value, field_key, item_id, f.type'
419 );
420
421 $entry->metas = array();
422
423 $include_key = apply_filters( 'frm_include_meta_keys', false, array( 'form_id' => $entry->form_id ) );
424 foreach ( $metas as $meta_val ) {
425 FrmFieldsHelper::prepare_field_value( $meta_val->meta_value, $meta_val->type );
426
427 if ( $meta_val->item_id == $entry->id ) {
428 $entry->metas[ $meta_val->field_id ] = $meta_val->meta_value;
429 if ( $include_key ) {
430 $entry->metas[ $meta_val->field_key ] = $entry->metas[ $meta_val->field_id ];
431 }
432 continue;
433 }
434
435 // include sub entries in an array
436 if ( ! isset( $entry->metas[ $meta_val->field_id ] ) ) {
437 $entry->metas[ $meta_val->field_id ] = array();
438 }
439
440 $entry->metas[ $meta_val->field_id ][] = $meta_val->meta_value;
441
442 unset( $meta_val );
443 }
444 unset( $metas );
445
446 FrmDb::set_cache( $entry->id, $entry, 'frm_entry' );
447
448 return $entry;
449 }
450
451 /**
452 * @param string $id
453 */
454 public static function exists( $id ) {
455 global $wpdb;
456
457 if ( FrmDb::check_cache( $id, 'frm_entry' ) ) {
458 $exists = true;
459
460 return $exists;
461 }
462
463 if ( is_numeric( $id ) ) {
464 $where = array( 'id' => $id );
465 } else {
466 $where = array( 'item_key' => $id );
467 }
468 $id = FrmDb::get_var( $wpdb->prefix . 'frm_items', $where );
469
470 return ( $id && $id > 0 );
471 }
472
473 public static function getAll( $where, $order_by = '', $limit = '', $meta = false, $inc_form = true ) {
474 global $wpdb;
475
476 $limit = FrmDb::esc_limit( $limit );
477
478 $cache_key = FrmAppHelper::maybe_json_encode( $where ) . $order_by . $limit . $inc_form;
479 $entries = wp_cache_get( $cache_key, 'frm_entry' );
480
481 if ( false === $entries ) {
482 $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';
483 $table = $wpdb->prefix . 'frm_items it ';
484
485 if ( $inc_form ) {
486 $fields = 'it.*, fr.name as form_name,fr.form_key as form_key';
487 $table .= 'LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_forms fr ON it.form_id=fr.id ';
488 }
489
490 if ( preg_match( '/ meta_([0-9]+)/', $order_by, $order_matches ) ) {
491 $fields .= self::sort_by_field( $order_matches[1] );
492 unset( $order_matches );
493 }
494
495 // prepare the query
496 $query = 'SELECT ' . $fields . ' FROM ' . $table . FrmDb::prepend_and_or_where( ' WHERE ', $where ) . $order_by . $limit;
497
498 $entries = $wpdb->get_results( $query, OBJECT_K ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
499 unset( $query );
500
501 FrmDb::set_cache( $cache_key, $entries, 'frm_entry' );
502 }
503
504 if ( ! $meta || ! $entries ) {
505 self::prepare_entries( $entries );
506 return $entries;
507 }
508 unset( $meta );
509
510 if ( ! is_array( $where ) && preg_match( '/^it\.form_id=\d+$/', $where ) ) {
511 $where = array( 'it.form_id' => substr( $where, 11 ) );
512 }
513
514 $meta_where = array( 'field_id !' => 0 );
515 if ( $limit == '' && is_array( $where ) && count( $where ) == 1 && isset( $where['it.form_id'] ) ) {
516 $meta_where['fi.form_id'] = $where['it.form_id'];
517 } else {
518 $meta_where['item_id'] = array_keys( $entries );
519 }
520
521 $metas = FrmDb::get_results(
522 $wpdb->prefix . 'frm_item_metas it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_fields fi ON it.field_id = fi.id',
523 $meta_where,
524 'item_id, meta_value, field_id, field_key, form_id, fi.type'
525 );
526
527 unset( $meta_where );
528
529 if ( ! $metas ) {
530 self::prepare_entries( $entries );
531 return $entries;
532 }
533
534 foreach ( $metas as $m_key => $meta_val ) {
535 if ( ! isset( $entries[ $meta_val->item_id ] ) ) {
536 continue;
537 }
538
539 if ( ! isset( $entries[ $meta_val->item_id ]->metas ) ) {
540 $entries[ $meta_val->item_id ]->metas = array();
541 }
542
543 FrmFieldsHelper::prepare_field_value( $meta_val->meta_value, $meta_val->type );
544 $entries[ $meta_val->item_id ]->metas[ $meta_val->field_id ] = $meta_val->meta_value;
545 unset( $m_key, $meta_val );
546 }
547
548 if ( ! FrmAppHelper::prevent_caching() ) {
549 foreach ( $entries as $entry ) {
550 FrmDb::set_cache( $entry->id, $entry, 'frm_entry' );
551 unset( $entry );
552 }
553 }
554
555 self::prepare_entries( $entries );
556 return $entries;
557 }
558
559 /**
560 * @param int $field_id
561 * @return string
562 */
563 private static function sort_by_field( $field_id ) {
564 global $wpdb;
565 $field_id = (int) $field_id;
566
567 $field_options = FrmDb::get_var( 'frm_fields', array( 'id' => $field_id ), 'field_options' );
568 FrmAppHelper::unserialize_or_decode( $field_options );
569
570 if ( empty( $field_options['post_field'] ) ) {
571 $sort = ', (SELECT meta_value FROM ' . $wpdb->prefix . 'frm_item_metas WHERE field_id = ' . $field_id . ' AND item_id = it.id) as meta_' . $field_id;
572 } else {
573 $sort = '';
574 }
575
576 return apply_filters( 'frm_handle_field_column_sort', $sort, $field_id, $field_options );
577 }
578
579 // Pagination Methods
580 /**
581 * @param int|array|string If int, use the form id.
582 */
583 public static function getRecordCount( $where = '' ) {
584 global $wpdb;
585 $table_join = $wpdb->prefix . 'frm_items it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_forms fr ON it.form_id=fr.id';
586
587 if ( is_numeric( $where ) ) {
588 $table_join = 'frm_items';
589 $where = array( 'form_id' => $where );
590 }
591
592 if ( is_array( $where ) ) {
593 $count = FrmDb::get_count( $table_join, $where );
594 } else {
595 $cache_key = 'count_' . FrmAppHelper::maybe_json_encode( $where );
596 $query = 'SELECT COUNT(*) FROM ' . $table_join . FrmDb::prepend_and_or_where( ' WHERE ', $where );
597 $count = FrmDb::check_cache( $cache_key, 'frm_entry', $query, 'get_var' );
598 }
599
600 return $count;
601 }
602
603 public static function getPageCount( $p_size, $where = '' ) {
604 $p_size = (int) $p_size;
605 $count = 1;
606 if ( $p_size ) {
607 if ( ! is_numeric( $where ) ) {
608 $where = self::getRecordCount( $where );
609 }
610 $count = ceil( (int) $where / $p_size );
611 }
612
613 return $count;
614 }
615
616 /**
617 * Prepare the data before inserting it into the database
618 *
619 * @since 2.0.16
620 *
621 * @param array $values
622 * @param string $type
623 *
624 * @return array $new_values
625 */
626 private static function before_insert_entry_in_database( &$values, $type ) {
627
628 self::sanitize_entry_post( $values );
629
630 if ( $type != 'xml' ) {
631 $values = apply_filters( 'frm_pre_create_entry', $values );
632 }
633
634 $new_values = self::package_entry_data( $values );
635
636 return $new_values;
637 }
638
639 /**
640 * Create an entry and perform after create actions
641 *
642 * @since 2.0.16
643 *
644 * @param array $values
645 * @param array $new_values
646 *
647 * @return boolean|int $entry_id
648 */
649 private static function continue_to_create_entry( $values, $new_values ) {
650 $entry_id = self::insert_entry_into_database( $new_values );
651 if ( ! $entry_id ) {
652 return false;
653 }
654
655 self::after_insert_entry_in_database( $values, $new_values, $entry_id );
656
657 return $entry_id;
658 }
659
660 /**
661 * Sanitize the POST values before we use them
662 *
663 * @since 2.0
664 *
665 * @param array $values The POST values by reference
666 */
667 public static function sanitize_entry_post( &$values ) {
668 $sanitize_method = array(
669 'form_id' => 'absint',
670 'frm_action' => 'sanitize_title',
671 'form_key' => 'sanitize_title',
672 'item_key' => 'sanitize_title',
673 'item_name' => 'sanitize_text_field',
674 'frm_saving_draft' => 'absint',
675 'is_draft' => 'absint',
676 'post_id' => 'absint',
677 'parent_item_id' => 'absint',
678 'created_at' => 'sanitize_text_field',
679 'updated_at' => 'sanitize_text_field',
680 );
681
682 FrmAppHelper::sanitize_request( $sanitize_method, $values );
683 }
684
685 /**
686 * Prepare the new values for inserting into the database
687 *
688 * @since 2.0.16
689 *
690 * @param array $values
691 *
692 * @return array $new_values
693 */
694 private static function package_entry_data( &$values ) {
695 global $wpdb;
696
697 if ( ! isset( $values['item_key'] ) ) {
698 $values['item_key'] = '';
699 }
700
701 $item_name = self::get_new_entry_name( $values, $values['item_key'] );
702 $new_values = array(
703 'item_key' => FrmAppHelper::get_unique_key( $values['item_key'], $wpdb->prefix . 'frm_items', 'item_key' ),
704 'name' => FrmAppHelper::truncate( $item_name, 255, 1, '' ),
705 'ip' => self::get_ip( $values ),
706 'is_draft' => self::get_is_draft_value( $values ),
707 'form_id' => (int) self::get_entry_value( $values, 'form_id', null ),
708 'post_id' => (int) self::get_entry_value( $values, 'post_id', 0 ),
709 'parent_item_id' => (int) self::get_entry_value( $values, 'parent_item_id', 0 ),
710 'created_at' => self::get_created_at( $values ),
711 'updated_at' => self::get_updated_at( $values ),
712 'description' => self::get_entry_description( $values ),
713 'user_id' => self::get_entry_user_id( $values ),
714 );
715
716 $new_values['updated_by'] = isset( $values['updated_by'] ) ? $values['updated_by'] : $new_values['user_id'];
717
718 return $new_values;
719 }
720
721 private static function get_entry_value( $values, $name, $default ) {
722 return isset( $values[ $name ] ) ? $values[ $name ] : $default;
723 }
724
725 /**
726 * Get the ip for a new entry.
727 * Allow the import to override the value.
728 *
729 * @since 2.03.10
730 *
731 * @param array $values
732 *
733 * @return string
734 */
735 private static function get_ip( $values ) {
736 if ( ! FrmAppHelper::ips_saved() ) {
737 return '';
738 }
739
740 $ip = FrmAppHelper::get_ip_address();
741 if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
742 $ip = self::get_entry_value( $values, 'ip', $ip );
743 }
744
745 return $ip;
746 }
747
748 /**
749 * Get the is_draft value for a new entry
750 *
751 * @since 2.0.16
752 *
753 * @param array $values
754 *
755 * @return int
756 */
757 private static function get_is_draft_value( $values ) {
758 return ( ( isset( $values['frm_saving_draft'] ) && $values['frm_saving_draft'] == 1 ) || ( isset( $values['is_draft'] ) && $values['is_draft'] == 1 ) ) ? 1 : 0;
759 }
760
761 /**
762 * Get the created_at value for a new entry
763 *
764 * @since 2.0.16
765 *
766 * @param array $values
767 *
768 * @return string
769 */
770 private static function get_created_at( $values ) {
771 return self::get_entry_value( $values, 'created_at', current_time( 'mysql', 1 ) );
772 }
773
774 /**
775 * Get the updated_at value for a new entry
776 *
777 * @since 2.0.16
778 *
779 * @param array $values
780 *
781 * @return string
782 */
783 private static function get_updated_at( $values ) {
784 if ( isset( $values['updated_at'] ) ) {
785 $updated_at = $values['updated_at'];
786 } else {
787 $updated_at = self::get_created_at( $values );
788 }
789
790 return $updated_at;
791 }
792
793 /**
794 * Get the description value for a new entry
795 *
796 * @since 2.0.16
797 *
798 * @param array $values
799 *
800 * @return string
801 */
802 private static function get_entry_description( $values ) {
803 if ( isset( $values['description'] ) && ! empty( $values['description'] ) ) {
804 $description = FrmAppHelper::maybe_json_encode( $values['description'] );
805 } else {
806 $description = json_encode(
807 array(
808 'browser' => FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' ),
809 'referrer' => FrmAppHelper::get_server_value( 'HTTP_REFERER' ),
810 )
811 );
812 }
813
814 return $description;
815 }
816
817 /**
818 * Get the user_id value for a new entry
819 *
820 * @since 2.0.16
821 *
822 * @param array $values
823 *
824 * @return int
825 */
826 private static function get_entry_user_id( $values ) {
827 if ( isset( $values['frm_user_id'] ) && ( is_numeric( $values['frm_user_id'] ) || FrmAppHelper::is_admin() ) ) {
828 $user_id = $values['frm_user_id'];
829 } else {
830 $current_user_id = get_current_user_id();
831 $user_id = $current_user_id ? $current_user_id : 0;
832 }
833
834 return $user_id;
835 }
836
837 /**
838 * Insert new entry into the database
839 *
840 * @since 2.0.16
841 *
842 * @param array $new_values
843 *
844 * @return int | boolean $entry_id
845 */
846 private static function insert_entry_into_database( $new_values ) {
847 global $wpdb;
848
849 $query_results = $wpdb->insert( $wpdb->prefix . 'frm_items', $new_values );
850
851 if ( ! $query_results ) {
852 $entry_id = false;
853 } else {
854 $entry_id = $wpdb->insert_id;
855 }
856
857 return $entry_id;
858 }
859
860 /**
861 * Add the new entry to global $frm_vars
862 *
863 * @since 2.0.16
864 *
865 * @param int $entry_id
866 */
867 private static function add_new_entry_to_frm_vars( $entry_id ) {
868 global $frm_vars;
869
870 if ( ! isset( $frm_vars['saved_entries'] ) ) {
871 $frm_vars['saved_entries'] = array();
872 }
873
874 $frm_vars['saved_entries'][] = (int) $entry_id;
875 }
876
877 /**
878 * Add entry metas, if there are any
879 *
880 * @since 2.0.16
881 *
882 * @param array $values
883 * @param int $entry_id
884 * @return void
885 */
886 private static function maybe_add_entry_metas( $values, $entry_id ) {
887 if ( isset( $values['item_meta'] ) ) {
888 FrmEntryMeta::update_entry_metas( $entry_id, $values['item_meta'] );
889 }
890 self::maybe_add_captcha_meta( (int) $values['form_id'], (int) $entry_id );
891 }
892
893 /**
894 * @since 5.0.15
895 *
896 * @param int $form_id
897 * @param int $entry_id
898 * @return void
899 */
900 private static function maybe_add_captcha_meta( $form_id, $entry_id ) {
901 global $frm_vars;
902 if ( array_key_exists( 'captcha_scores', $frm_vars ) && array_key_exists( $form_id, $frm_vars['captcha_scores'] ) ) {
903 $captcha_score_meta = array( 'captcha_score' => $frm_vars['captcha_scores'][ $form_id ] );
904 FrmEntryMeta::add_entry_meta( $entry_id, 0, '', maybe_serialize( $captcha_score_meta ) );
905 }
906 }
907
908 /**
909 * Trigger frm_after_create_entry hooks
910 *
911 * @since 2.0.16
912 *
913 * @param int $entry_id
914 * @param array $new_values
915 */
916 private static function after_entry_created_actions( $entry_id, $values, $new_values ) {
917 // this is a child entry
918 $is_child = isset( $values['parent_form_id'] ) && isset( $values['parent_nonce'] ) && ! empty( $values['parent_form_id'] ) && wp_verify_nonce( $values['parent_nonce'], 'parent' );
919
920 do_action( 'frm_after_create_entry', $entry_id, $new_values['form_id'], compact( 'is_child' ) );
921 do_action( 'frm_after_create_entry_' . $new_values['form_id'], $entry_id, compact( 'is_child' ) );
922 }
923
924 /**
925 * Actions to perform immediately after an entry is inserted in the frm_items database
926 *
927 * @since 2.0.16
928 *
929 * @param array $values
930 * @param array $new_values
931 * @param int $entry_id
932 */
933 private static function after_insert_entry_in_database( $values, $new_values, $entry_id ) {
934
935 self::add_new_entry_to_frm_vars( $entry_id );
936
937 self::maybe_add_entry_metas( $values, $entry_id );
938
939 self::clear_cache();
940
941 self::after_entry_created_actions( $entry_id, $values, $new_values );
942 }
943
944 /**
945 * Perform some actions right before updating an entry
946 *
947 * @since 2.0.16
948 *
949 * @param int $id
950 * @param array $values
951 * @param string $update_type
952 *
953 * @return boolean $update
954 */
955 private static function before_update_entry( $id, &$values, $update_type ) {
956 $update = true;
957
958 global $frm_vars;
959
960 if ( isset( $frm_vars['saved_entries'] ) && is_array( $frm_vars['saved_entries'] ) && in_array( (int) $id, (array) $frm_vars['saved_entries'] ) ) {
961 $update = false;
962 }
963
964 if ( $update && $update_type != 'xml' ) {
965 $values = apply_filters( 'frm_pre_update_entry', $values, $id );
966 }
967
968 return $update;
969 }
970
971 /**
972 * Package the entry data for updating
973 *
974 * @since 2.0.16
975 *
976 * @param int $id
977 * @param array $values
978 *
979 * @return array $new_values
980 */
981 private static function package_entry_to_update( $id, $values ) {
982 global $wpdb;
983
984 $new_values = array(
985 'name' => self::get_new_entry_name( $values ),
986 'form_id' => (int) self::get_entry_value( $values, 'form_id', null ),
987 'is_draft' => self::get_is_draft_value( $values ),
988 'updated_at' => current_time( 'mysql', 1 ),
989 'updated_by' => isset( $values['updated_by'] ) ? $values['updated_by'] : get_current_user_id(),
990 );
991
992 if ( isset( $values['post_id'] ) ) {
993 $new_values['post_id'] = (int) $values['post_id'];
994 }
995
996 if ( isset( $values['item_key'] ) ) {
997 $new_values['item_key'] = FrmAppHelper::get_unique_key( $values['item_key'], $wpdb->prefix . 'frm_items', 'item_key', $id );
998 }
999
1000 if ( isset( $values['parent_item_id'] ) ) {
1001 $new_values['parent_item_id'] = (int) $values['parent_item_id'];
1002 }
1003
1004 if ( isset( $values['frm_user_id'] ) && is_numeric( $values['frm_user_id'] ) ) {
1005 $new_values['user_id'] = $values['frm_user_id'];
1006 }
1007
1008 $new_values = apply_filters( 'frm_update_entry', $new_values, $id );
1009
1010 return $new_values;
1011 }
1012
1013 /**
1014 * Perform some actions right after updating an entry
1015 *
1016 * @since 2.0.16
1017 *
1018 * @param boolean|int $query_results
1019 * @param int $id
1020 * @param array $values
1021 * @param array $new_values
1022 */
1023 private static function after_update_entry( $query_results, $id, $values, $new_values ) {
1024 if ( $query_results ) {
1025 self::clear_cache();
1026 }
1027
1028 global $frm_vars;
1029 if ( ! isset( $frm_vars['saved_entries'] ) ) {
1030 $frm_vars['saved_entries'] = array();
1031 }
1032
1033 $frm_vars['saved_entries'][] = (int) $id;
1034
1035 if ( isset( $values['item_meta'] ) ) {
1036 FrmEntryMeta::update_entry_metas( $id, $values['item_meta'] );
1037 }
1038
1039 do_action( 'frm_after_update_entry', $id, $new_values['form_id'] );
1040 do_action( 'frm_after_update_entry_' . $new_values['form_id'], $id );
1041 }
1042
1043 /**
1044 * Create entry from an XML import
1045 * Certain actions aren't necessary when importing (like saving sub entries, checking for duplicates, etc.)
1046 *
1047 * @since 2.0.16
1048 *
1049 * @param array $values
1050 *
1051 * @return int | boolean $entry_id
1052 */
1053 public static function create_entry_from_xml( $values ) {
1054 $entry_id = self::create_entry( $values, 'xml' );
1055
1056 return $entry_id;
1057 }
1058
1059 /**
1060 * Update entry from an XML import
1061 * Certain actions aren't necessary when importing (like saving sub entries and modifying other vals)
1062 *
1063 * @since 2.0.16
1064 *
1065 * @param int $id
1066 * @param array $values
1067 *
1068 * @return int | boolean $updated
1069 */
1070 public static function update_entry_from_xml( $id, $values ) {
1071 $updated = self::update_entry( $id, $values, 'xml' );
1072
1073 return $updated;
1074 }
1075
1076 /**
1077 * @param string $key
1078 *
1079 * @return int entry_id
1080 */
1081 public static function get_id_by_key( $key ) {
1082 $entry_id = FrmDb::get_var( 'frm_items', array( 'item_key' => sanitize_title( $key ) ) );
1083
1084 return (int) $entry_id;
1085 }
1086 }
1087