Completed
Branch master (ad2140)
by Stephanie
02:50
created

FrmEntry::get_created_at()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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
	* @return int | boolean $entry_id
13
	*/
14
	public static function create( $values ) {
15
		$entry_id = self::create_entry( $values, 'standard' );
16
17
		return $entry_id;
18
	}
19
20
	/**
21
	* Create a new entry with some differences depending on type
22
	*
23
	* @param array $values
24
	* @param string $type
25
	* @return int | boolean $entry_id
26
	*/
27
	private static function create_entry( $values, $type ) {
28
		$new_values = self::before_insert_entry_in_database( $values, $type );
29
30
		// Don't check XML entries for duplicates
31
		if ( $type != 'xml' && self::is_duplicate( $new_values, $values ) ) {
32
			return false;
33
		}
34
35
		$entry_id = self::continue_to_create_entry( $values, $new_values );
36
37
		return $entry_id;
38
	}
39
40
    /**
41
     * check for duplicate entries created in the last minute
42
     * @return boolean
43
     */
44
	public static function is_duplicate( $new_values, $values ) {
45
		$duplicate_entry_time = apply_filters( 'frm_time_to_check_duplicates', 60, $new_values );
46
47
		if ( false === self::is_duplicate_check_needed( $values, $duplicate_entry_time ) ) {
48
			return false;
49
		}
50
51
        $check_val = $new_values;
52
		$check_val['created_at >'] = date( 'Y-m-d H:i:s', ( strtotime( $new_values['created_at'] ) - absint( $duplicate_entry_time ) ) );
53
54
		unset( $check_val['created_at'], $check_val['updated_at'] );
55
		unset( $check_val['is_draft'], $check_val['id'], $check_val['item_key'] );
56
57
        if ( $new_values['item_key'] == $new_values['name'] ) {
58
            unset($check_val['name']);
59
        }
60
61
        global $wpdb;
62
		$entry_exists = FrmDb::get_col( $wpdb->prefix . 'frm_items', $check_val, 'id', array( 'order_by' => 'created_at DESC' ) );
63
64
        if ( ! $entry_exists || empty($entry_exists) || ! isset($values['item_meta']) ) {
65
            return false;
66
        }
67
68
        $is_duplicate = false;
69
        foreach ( $entry_exists as $entry_exist ) {
0 ignored issues
show
Bug introduced by
The expression $entry_exists of type array|string|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
70
            $is_duplicate = true;
71
72
            //add more checks here to make sure it's a duplicate
73
            $metas = FrmEntryMeta::get_entry_meta_info($entry_exist);
74
            $field_metas = array();
75
            foreach ( $metas as $meta ) {
0 ignored issues
show
Bug introduced by
The expression $metas of type array|null|string|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
76
				$field_metas[ $meta->field_id ] = $meta->meta_value;
77
            }
78
79
            // If prev entry is empty and current entry is not, they are not duplicates
80
            $filtered_vals = array_filter( $values['item_meta'] );
81
            if ( empty( $field_metas ) && ! empty( $filtered_vals ) ) {
82
                return false;
83
            }
84
85
            $diff = array_diff_assoc($field_metas, array_map('maybe_serialize', $values['item_meta']));
86
            foreach ( $diff as $field_id => $meta_value ) {
87
                if ( ! empty($meta_value) ) {
88
                    $is_duplicate = false;
89
                    continue;
90
                }
91
            }
92
93
            if ( $is_duplicate ) {
94
				break;
95
            }
96
        }
97
98
        return $is_duplicate;
99
    }
100
101
	/**
102
	 * Determine if an entry needs to be checked as a possible duplicate
103
	 *
104
	 * @since 2.0.23
105
	 * @param array $values
106
	 * @param int $duplicate_entry_time
107
	 * @return bool
108
	 */
109
	private static function is_duplicate_check_needed( $values, $duplicate_entry_time ) {
110
		// If time for checking duplicates is set to an empty value, don't check for duplicates
111
		if ( empty( $duplicate_entry_time ) ) {
112
			return false;
113
		}
114
115
		// If CSV is importing, don't check for duplicates
116
		if ( defined('WP_IMPORTING') && WP_IMPORTING ) {
117
			return false;
118
		}
119
120
		// If repeating field entries are getting created, don't check for duplicates
121
		if ( isset( $values['parent_form_id'] ) && $values['parent_form_id'] ) {
122
			return false;
123
		}
124
125
		return true;
126
	}
127
128
	public static function duplicate( $id ) {
129
		global $wpdb;
130
131
		$values = self::getOne( $id );
132
133
		$new_values = array();
134
		$new_values['item_key']   = FrmAppHelper::get_unique_key( '', $wpdb->prefix . 'frm_items', 'item_key' );
135
		$new_values['name']       = $values->name;
136
		$new_values['is_draft']   = $values->is_draft;
137
		$new_values['user_id']    = (int) $values->user_id;
138
		$new_values['updated_by'] = (int) $values->user_id;
139
		$new_values['form_id']    = $values->form_id ? (int) $values->form_id : null;
140
		$new_values['created_at'] = current_time( 'mysql', 1 );
141
		$new_values['updated_at'] = $new_values['created_at'];
142
143
		$query_results = $wpdb->insert( $wpdb->prefix . 'frm_items', $new_values );
144
        if ( ! $query_results ) {
145
            return false;
146
        }
147
148
        $entry_id = $wpdb->insert_id;
149
150
        global $frm_vars;
151
        if ( ! isset($frm_vars['saved_entries']) ) {
152
            $frm_vars['saved_entries'] = array();
153
        }
154
        $frm_vars['saved_entries'][] = (int) $entry_id;
155
156
        FrmEntryMeta::duplicate_entry_metas($id, $entry_id);
157
		self::clear_cache();
158
159
		do_action( 'frm_after_duplicate_entry', $entry_id, $new_values['form_id'], array( 'old_id' => $id ) );
160
        return $entry_id;
161
    }
162
163
	/**
164
	* Update an entry (not via XML)
165
	*
166
	* @param int $id
167
	* @param array $values
168
	* @return boolean|int $update_results
169
	*/
170
	public static function update( $id, $values ) {
171
		$update_results = self::update_entry( $id, $values, 'standard' );
172
173
		return $update_results;
174
	}
175
176
	/**
177
	* Update an entry with some differences depending on the update type
178
	*
179
	* @since 2.0.16
180
	*
181
	* @param int $id
182
	* @param array $values
183
	* @return boolean|int $query_results
184
	*/
185
	private static function update_entry( $id, $values, $update_type ) {
186
		global $wpdb;
187
188
		$update = self::before_update_entry( $id, $values, $update_type );
189
		if ( ! $update ) {
190
			return false;
191
		}
192
193
		$new_values = self::package_entry_to_update( $id, $values );
194
195
		$query_results = $wpdb->update( $wpdb->prefix . 'frm_items', $new_values, compact('id') );
196
197
		self::after_update_entry( $query_results, $id, $values, $new_values );
198
199
		return $query_results;
200
	}
201
202
	public static function destroy( $id ) {
203
        global $wpdb;
204
        $id = (int) $id;
205
206
		$entry = self::getOne( $id );
207
        if ( ! $entry ) {
208
            $result = false;
209
            return $result;
210
        }
211
212
        do_action('frm_before_destroy_entry', $id, $entry);
213
214
		$wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_item_metas WHERE item_id=%d', $id ) );
215
		$result = $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_items WHERE id=%d', $id ) );
216
217
		self::clear_cache();
218
219
        return $result;
220
    }
221
222
	public static function update_form( $id, $value, $form_id ) {
223
        global $wpdb;
224
        $form_id = isset($value) ? $form_id : null;
225
		$result = $wpdb->update( $wpdb->prefix . 'frm_items', array( 'form_id' => $form_id ), array( 'id' => $id ) );
226
		if ( $result ) {
227
			self::clear_cache();
228
		}
229
        return $result;
230
    }
231
232
	/**
233
	 * Clear entry caching
234
	 * Called when an entry is changed
235
	 *
236
	 * @since 2.0.5
237
	 */
238
	public static function clear_cache() {
239
		FrmDb::cache_delete_group( 'frm_entry' );
240
		FrmDb::cache_delete_group( 'frm_item' );
241
		FrmDb::cache_delete_group( 'frm_entry_meta' );
242
		FrmDb::cache_delete_group( 'frm_item_meta' );
243
	}
244
245
	/**
246
	 * After switching to the wp_loaded hook for processing entries,
247
	 * we can no longer use 'name', but check it as a fallback
248
	 * @since 2.0.11
249
	 */
250
	public static function get_new_entry_name( $values, $default = '' ) {
251
		$name = isset( $values['item_name'] ) ? $values['item_name'] : ( isset( $values['name'] ) ? $values['name'] : $default );
252
		if ( is_array( $name ) ) {
253
			$name = reset( $name );
254
		}
255
		return $name;
256
	}
257
258
	/**
259
	 * If $entry is numeric, get the entry object
260
	 * @param int|object $entry by reference
261
	 * @since 2.0.9
262
	 */
263
	public static function maybe_get_entry( &$entry ) {
264
		if ( $entry && is_numeric( $entry ) ) {
265
			$entry = self::getOne( $entry );
266
		} elseif ( empty( $entry ) ) {
267
			$entry = false;
268
		}
269
	}
270
271
	public static function getOne( $id, $meta = false ) {
0 ignored issues
show
Coding Style introduced by
The function name getOne is in camel caps, but expected get_one instead as per the coding standard.
Loading history...
272
        global $wpdb;
273
274
        $query = "SELECT it.*, fr.name as form_name, fr.form_key as form_key FROM {$wpdb->prefix}frm_items it
275
                  LEFT OUTER JOIN {$wpdb->prefix}frm_forms fr ON it.form_id=fr.id WHERE ";
276
277
        $query .= is_numeric($id) ? 'it.id=%d' : 'it.item_key=%s';
278
        $query_args = array( $id );
279
        $query = $wpdb->prepare( $query, $query_args );
280
281
        if ( ! $meta ) {
282
			$entry = FrmDb::check_cache( $id . '_nometa', 'frm_entry', $query, 'get_row' );
283
            return stripslashes_deep($entry);
284
        }
285
286
        $entry = FrmDb::check_cache( $id, 'frm_entry' );
287
        if ( $entry !== false ) {
288
            return stripslashes_deep($entry);
289
        }
290
291
        $entry = $wpdb->get_row( $query );
292
        $entry = self::get_meta($entry);
293
294
        return stripslashes_deep($entry);
295
    }
296
297
	public static function get_meta( $entry ) {
298
        if ( ! $entry ) {
299
            return $entry;
300
        }
301
302
        global $wpdb;
303
		$metas = FrmDb::get_results( $wpdb->prefix . 'frm_item_metas m LEFT JOIN ' . $wpdb->prefix . 'frm_fields f ON m.field_id=f.id', array(
304
			'item_id' => $entry->id,
305
			'field_id !' => 0,
306
		), 'field_id, meta_value, field_key, item_id' );
307
308
        $entry->metas = array();
309
310
		$include_key = apply_filters( 'frm_include_meta_keys', false, array( 'form_id' => $entry->form_id ) );
311
        foreach ( $metas as $meta_val ) {
0 ignored issues
show
Bug introduced by
The expression $metas of type array|null|string|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
312
            if ( $meta_val->item_id == $entry->id ) {
313
				$entry->metas[ $meta_val->field_id ] = maybe_unserialize( $meta_val->meta_value );
314
				if ( $include_key ) {
315
					$entry->metas[ $meta_val->field_key ] = $entry->metas[ $meta_val->field_id ];
316
				}
317
                 continue;
318
            }
319
320
            // include sub entries in an array
321
			if ( ! isset( $entry_metas[ $meta_val->field_id ] ) ) {
322
				$entry->metas[ $meta_val->field_id ] = array();
323
            }
324
325
			$entry->metas[ $meta_val->field_id ][] = maybe_unserialize( $meta_val->meta_value );
326
327
            unset($meta_val);
328
        }
329
        unset($metas);
330
331
		FrmDb::set_cache( $entry->id, $entry, 'frm_entry' );
332
333
        return $entry;
334
    }
335
336
    /**
337
     * @param string $id
338
     */
339
	public static function exists( $id ) {
340
        global $wpdb;
341
342
        if ( FrmDb::check_cache( $id, 'frm_entry' ) ) {
343
            $exists = true;
344
            return $exists;
345
        }
346
347
        if ( is_numeric($id) ) {
348
            $where = array( 'id' => $id );
349
        } else {
350
            $where = array( 'item_key' => $id );
351
        }
352
		$id = FrmDb::get_var( $wpdb->prefix . 'frm_items', $where );
353
354
		return ( $id && $id > 0 );
355
    }
356
357
    public static function getAll( $where, $order_by = '', $limit = '', $meta = false, $inc_form = true ) {
0 ignored issues
show
Coding Style introduced by
The function name getAll is in camel caps, but expected get_all instead as per the coding standard.
Loading history...
358
		global $wpdb;
359
360
        $limit = FrmDb::esc_limit($limit);
361
362
        $cache_key = maybe_serialize($where) . $order_by . $limit . $inc_form;
363
        $entries = wp_cache_get($cache_key, 'frm_entry');
364
365
        if ( false === $entries ) {
366
            $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';
367
			$table = $wpdb->prefix . 'frm_items it ';
368
369
            if ( $inc_form ) {
370
                $fields = 'it.*, fr.name as form_name,fr.form_key as form_key';
371
                $table .= 'LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_forms fr ON it.form_id=fr.id ';
372
            }
373
374
            if ( preg_match( '/ meta_([0-9]+)/', $order_by, $order_matches ) ) {
375
    		    // sort by a requested field
376
                $field_id = (int) $order_matches[1];
377
				$fields .= ', (SELECT meta_value FROM ' . $wpdb->prefix . 'frm_item_metas WHERE field_id = ' . $field_id . ' AND item_id = it.id) as meta_' . $field_id;
378
				unset( $order_matches, $field_id );
379
		    }
380
381
			// prepare the query
382
			$query = 'SELECT ' . $fields . ' FROM ' . $table . FrmDb::prepend_and_or_where(' WHERE ', $where) . $order_by . $limit;
383
384
            $entries = $wpdb->get_results($query, OBJECT_K);
385
            unset($query);
386
387
			FrmDb::set_cache( $cache_key, $entries, 'frm_entry' );
388
        }
389
390
        if ( ! $meta || ! $entries ) {
391
            return stripslashes_deep($entries);
392
        }
393
        unset($meta);
394
395
        if ( ! is_array( $where ) && preg_match('/^it\.form_id=\d+$/', $where) ) {
396
			$where = array( 'it.form_id' => substr( $where, 11 ) );
397
        }
398
399
        $meta_where = array( 'field_id !' => 0 );
400
        if ( $limit == '' && is_array($where) && count($where) == 1 && isset($where['it.form_id']) ) {
401
            $meta_where['fi.form_id'] = $where['it.form_id'];
402
        } else {
403
            $meta_where['item_id'] = array_keys( $entries );
404
        }
405
406
        $metas = FrmDb::get_results( $wpdb->prefix . 'frm_item_metas it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_fields fi ON (it.field_id = fi.id)', $meta_where, 'item_id, meta_value, field_id, field_key, form_id' );
407
408
        unset( $meta_where );
409
410
        if ( ! $metas ) {
411
            return stripslashes_deep($entries);
412
        }
413
414
        foreach ( $metas as $m_key => $meta_val ) {
0 ignored issues
show
Bug introduced by
The expression $metas of type array|string|object is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
415
            if ( ! isset( $entries[ $meta_val->item_id ] ) ) {
416
                continue;
417
            }
418
419
            if ( ! isset( $entries[ $meta_val->item_id ]->metas ) ) {
420
				$entries[ $meta_val->item_id ]->metas = array();
421
            }
422
423
			$entries[ $meta_val->item_id ]->metas[ $meta_val->field_id ] = maybe_unserialize( $meta_val->meta_value );
424
425
            unset($m_key, $meta_val);
426
        }
427
428
		if ( ! FrmAppHelper::prevent_caching() ) {
429
			foreach ( $entries as $entry ) {
430
				FrmDb::set_cache( $entry->id, $entry, 'frm_entry' );
431
				unset( $entry );
432
			}
433
		}
434
435
        return stripslashes_deep($entries);
436
    }
437
438
    // Pagination Methods
439
    public static function getRecordCount( $where = '' ) {
0 ignored issues
show
Coding Style introduced by
The function name getRecordCount is in camel caps, but expected get_record_count instead as per the coding standard.
Loading history...
440
        global $wpdb;
441
		$table_join = $wpdb->prefix . 'frm_items it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_forms fr ON it.form_id=fr.id';
442
443
        if ( is_numeric($where) ) {
444
            $table_join = 'frm_items';
445
            $where = array( 'form_id' => $where );
446
        }
447
448
        if ( is_array( $where ) ) {
449
            $count = FrmDb::get_count( $table_join, $where );
450
        } else {
451
			$cache_key = 'count_' . maybe_serialize( $where );
452
			$query = 'SELECT COUNT(*) FROM ' . $table_join . FrmDb::prepend_and_or_where( ' WHERE ', $where );
453
			$count = FrmDb::check_cache( $cache_key, 'frm_entry', $query, 'get_var' );
454
        }
455
456
        return $count;
457
    }
458
459
    public static function getPageCount( $p_size, $where = '' ) {
0 ignored issues
show
Coding Style introduced by
The function name getPageCount is in camel caps, but expected get_page_count instead as per the coding standard.
Loading history...
460
		$p_size = (int) $p_size;
461
		$count = 1;
462
		if ( $p_size ) {
463
			if ( ! is_numeric( $where ) ) {
464
				$where = self::getRecordCount( $where );
465
			}
466
			$count = ceil( (int) $where / $p_size );
467
		}
468
469
		return $count;
470
    }
471
472
	/**
473
	* Prepare the data before inserting it into the database
474
	*
475
	* @since 2.0.16
476
	* @param array $values
477
	* @param string $type
478
	* @return array $new_values
479
	*/
480
	private static function before_insert_entry_in_database( &$values, $type ) {
481
482
		self::sanitize_entry_post( $values );
483
484
		if ( $type != 'xml' ) {
485
			$values = apply_filters('frm_pre_create_entry', $values);
486
		}
487
488
		$new_values = self::package_entry_data( $values );
489
490
		return $new_values;
491
	}
492
493
	/**
494
	* Create an entry and perform after create actions
495
	*
496
	* @since 2.0.16
497
	* @param array $values
498
	* @param array $new_values
499
	* @return boolean|int $entry_id
500
	*/
501
	private static function continue_to_create_entry( $values, $new_values ) {
502
		$entry_id = self::insert_entry_into_database( $new_values );
503
		if ( ! $entry_id ) {
504
			return false;
505
		}
506
507
		self::after_insert_entry_in_database( $values, $new_values, $entry_id );
508
509
		return $entry_id;
510
	}
511
512
    /**
513
     * Sanitize the POST values before we use them
514
     *
515
     * @since 2.0
516
     * @param array $values The POST values by reference
517
     */
518
    public static function sanitize_entry_post( &$values ) {
519
        $sanitize_method = array(
520
            'form_id'       => 'absint',
521
            'frm_action'    => 'sanitize_title',
522
            'form_key'      => 'sanitize_title',
523
            'item_key'      => 'sanitize_title',
524
            'item_name'     => 'sanitize_text_field',
525
            'frm_saving_draft' => 'absint',
526
            'is_draft'      => 'absint',
527
            'post_id'       => 'absint',
528
            'parent_item_id' => 'absint',
529
            'created_at'    => 'sanitize_text_field',
530
            'updated_at'    => 'sanitize_text_field',
531
        );
532
533
        FrmAppHelper::sanitize_request( $sanitize_method, $values );
534
    }
535
536
	/**
537
	* Prepare the new values for inserting into the database
538
	*
539
	* @since 2.0.16
540
	* @param array $values
541
	* @return array $new_values
542
	*/
543
	private static function package_entry_data( &$values ) {
544
		global $wpdb;
545
546
		if ( ! isset( $values['item_key'] ) ) {
547
			$values['item_key'] = '';
548
		}
549
550
		$item_name = self::get_new_entry_name( $values, $values['item_key'] );
551
		$new_values = array(
552
			'item_key'  => FrmAppHelper::get_unique_key( $values['item_key'], $wpdb->prefix . 'frm_items', 'item_key' ),
553
			'name'      => FrmAppHelper::truncate( $item_name, 255, 1, '' ),
554
			'ip'        => self::get_ip( $values ),
555
			'is_draft'  => self::get_is_draft_value( $values ),
556
			'form_id'   => (int) self::get_entry_value( $values, 'form_id', null ),
557
			'post_id'   => (int) self::get_entry_value( $values, 'post_id', 0 ),
558
			'parent_item_id' => (int) self::get_entry_value( $values, 'parent_item_id', 0 ),
559
			'created_at' => self::get_created_at( $values ),
560
			'updated_at' => self::get_updated_at( $values ),
561
			'description' => self::get_entry_description( $values ),
562
			'user_id' => self::get_entry_user_id( $values ),
563
		);
564
565
		$new_values['updated_by'] = isset($values['updated_by']) ? $values['updated_by'] : $new_values['user_id'];
566
567
		return $new_values;
568
	}
569
570
	private static function get_entry_value( $values, $name, $default ) {
571
		return isset( $values[ $name ] ) ? $values[ $name ] : $default;
572
	}
573
574
	/**
575
	 * Get the ip for a new entry.
576
	 * Allow the import to override the value.
577
	 *
578
	 * @since 2.03.10
579
	 * @param array $values
580
	 * @return string
581
	 */
582
	private static function get_ip( $values ) {
583
		if ( ! FrmAppHelper::ips_saved() ) {
584
			return '';
585
		}
586
587
		$ip = FrmAppHelper::get_ip_address();
588
		if ( defined('WP_IMPORTING') && WP_IMPORTING ) {
589
			$ip = self::get_entry_value( $values, 'ip', $ip );
590
		}
591
		return $ip;
592
	}
593
594
	/**
595
	* Get the is_draft value for a new entry
596
	*
597
	* @since 2.0.16
598
	* @param array $values
599
	* @return int
600
	*/
601
	private static function get_is_draft_value( $values ) {
602
		return ( ( isset( $values['frm_saving_draft'] ) && $values['frm_saving_draft'] == 1 ) || ( isset( $values['is_draft'] ) && $values['is_draft'] == 1 ) ) ? 1 : 0;
603
	}
604
605
	/**
606
	* Get the created_at value for a new entry
607
	*
608
	* @since 2.0.16
609
	* @param array $values
610
	* @return string
611
	*/
612
	private static function get_created_at( $values ) {
613
		return self::get_entry_value( $values, 'created_at', current_time( 'mysql', 1 ) );
614
	}
615
616
	/**
617
	* Get the updated_at value for a new entry
618
	*
619
	* @since 2.0.16
620
	* @param array $values
621
	* @return string
622
	*/
623
	private static function get_updated_at( $values ) {
624
		if ( isset( $values['updated_at'] ) ) {
625
			$updated_at = $values['updated_at'];
626
		} else {
627
			$updated_at = self::get_created_at( $values );
628
		}
629
630
		return $updated_at;
631
	}
632
633
	/**
634
	* Get the description value for a new entry
635
	*
636
	* @since 2.0.16
637
	* @param array $values
638
	* @return string
639
	*/
640
	private static function get_entry_description( $values ) {
641
		if ( isset( $values['description'] ) && ! empty( $values['description'] ) ) {
642
			$description = maybe_serialize( $values['description'] );
643
		} else {
644
			$description = serialize( array(
645
				'browser'  => FrmAppHelper::get_server_value( 'HTTP_USER_AGENT' ),
646
				'referrer' => FrmAppHelper::get_server_value( 'HTTP_REFERER' ),
647
			) );
648
		}
649
650
		return $description;
651
	}
652
653
	/**
654
	* Get the user_id value for a new entry
655
	*
656
	* @since 2.0.16
657
	* @param array $values
658
	* @return int
659
	*/
660
	private static function get_entry_user_id( $values ) {
661
		if ( isset( $values['frm_user_id'] ) && ( is_numeric( $values['frm_user_id'] ) || FrmAppHelper::is_admin() ) ) {
662
			$user_id = $values['frm_user_id'];
663
		} else {
664
			$current_user_id = get_current_user_id();
665
			$user_id = $current_user_id ? $current_user_id : 0;
666
		}
667
668
		return $user_id;
669
	}
670
671
	/**
672
	* Insert new entry into the database
673
	*
674
	* @since 2.0.16
675
	* @param array $new_values
676
	* @return int | boolean $entry_id
677
	*/
678
	private static function insert_entry_into_database( $new_values ) {
679
		global $wpdb;
680
681
		$query_results = $wpdb->insert( $wpdb->prefix . 'frm_items', $new_values );
682
683
		if ( ! $query_results ) {
684
			$entry_id = false;
685
		} else {
686
			$entry_id = $wpdb->insert_id;
687
		}
688
689
		return $entry_id;
690
	}
691
692
	/**
693
	* Add the new entry to global $frm_vars
694
	*
695
	* @since 2.0.16
696
	* @param int $entry_id
697
	*/
698
	private static function add_new_entry_to_frm_vars( $entry_id ) {
699
		global $frm_vars;
700
701
		if ( ! isset($frm_vars['saved_entries']) ) {
702
			$frm_vars['saved_entries'] = array();
703
		}
704
705
		$frm_vars['saved_entries'][] = (int) $entry_id;
706
	}
707
708
	/**
709
	* Add entry metas, if there are any
710
	*
711
	* @since 2.0.16
712
	* @param array $values
713
	* @param int $entry_id
714
	*/
715
	private static function maybe_add_entry_metas( $values, $entry_id ) {
716
		if ( isset($values['item_meta']) ) {
717
			FrmEntryMeta::update_entry_metas( $entry_id, $values['item_meta'] );
718
		}
719
	}
720
721
	/**
722
	* Trigger frm_after_create_entry hooks
723
	*
724
	* @since 2.0.16
725
	* @param int $entry_id
726
	* @param array $new_values
727
	*/
728
	private static function after_entry_created_actions( $entry_id, $values, $new_values ) {
729
		// this is a child entry
730
		$is_child = isset( $values['parent_form_id'] ) && isset( $values['parent_nonce'] ) && ! empty( $values['parent_form_id'] ) && wp_verify_nonce( $values['parent_nonce'], 'parent' );
731
732
		do_action( 'frm_after_create_entry', $entry_id, $new_values['form_id'], compact( 'is_child' ) );
733
		do_action( 'frm_after_create_entry_' . $new_values['form_id'], $entry_id, compact( 'is_child' ) );
734
	}
735
736
	/**
737
	* Actions to perform immediately after an entry is inserted in the frm_items database
738
	*
739
	* @since 2.0.16
740
	* @param array $values
741
	* @param array $new_values
742
	* @param int $entry_id
743
	*/
744
	private static function after_insert_entry_in_database( $values, $new_values, $entry_id ) {
745
746
		self::add_new_entry_to_frm_vars( $entry_id );
747
748
		self::maybe_add_entry_metas( $values, $entry_id );
749
750
		self::clear_cache();
751
752
		self::after_entry_created_actions( $entry_id, $values, $new_values );
753
	}
754
755
	/**
756
	* Perform some actions right before updating an entry
757
	*
758
	* @since 2.0.16
759
	* @param int $id
760
	* @param array $values
761
	* @param string $update_type
762
	* @return boolean $update
763
	*/
764
	private static function before_update_entry( $id, &$values, $update_type ) {
765
		$update = true;
766
767
		global $frm_vars;
768
769
		if ( isset( $frm_vars['saved_entries'] ) && is_array( $frm_vars['saved_entries'] ) && in_array( (int) $id, (array) $frm_vars['saved_entries'] ) ) {
770
			$update = false;
771
		}
772
773
		if ( $update && $update_type != 'xml' ) {
774
			$values = apply_filters('frm_pre_update_entry', $values, $id);
775
		}
776
777
		return $update;
778
	}
779
780
	/**
781
	* Package the entry data for updating
782
	*
783
	* @since 2.0.16
784
	* @param int $id
785
	* @param array $values
786
	* @return array $new_values
787
	*/
788
	private static function package_entry_to_update( $id, $values ) {
789
		global $wpdb;
790
791
		$new_values = array(
792
			'name'      => self::get_new_entry_name( $values ),
793
			'form_id'   => (int) self::get_entry_value( $values, 'form_id', null ),
794
			'is_draft'  => self::get_is_draft_value( $values ),
795
			'updated_at' => current_time('mysql', 1),
796
			'updated_by' => isset($values['updated_by']) ? $values['updated_by'] : get_current_user_id(),
797
		);
798
799
		if ( isset($values['post_id']) ) {
800
			$new_values['post_id'] = (int) $values['post_id'];
801
		}
802
803
		if ( isset($values['item_key']) ) {
804
			$new_values['item_key'] = FrmAppHelper::get_unique_key( $values['item_key'], $wpdb->prefix . 'frm_items', 'item_key', $id );
805
		}
806
807
		if ( isset($values['parent_item_id']) ) {
808
			$new_values['parent_item_id'] = (int) $values['parent_item_id'];
809
		}
810
811
		if ( isset($values['frm_user_id']) && is_numeric($values['frm_user_id']) ) {
812
			$new_values['user_id'] = $values['frm_user_id'];
813
		}
814
815
		$new_values = apply_filters('frm_update_entry', $new_values, $id);
816
817
		return $new_values;
818
	}
819
820
	/**
821
	* Perform some actions right after updating an entry
822
	*
823
	* @since 2.0.16
824
	* @param boolean|int $query_results
825
	* @param int $id
826
	* @param array $values
827
	* @param array $new_values
828
	*/
829
	private static function after_update_entry( $query_results, $id, $values, $new_values ) {
830
		if ( $query_results ) {
831
			self::clear_cache();
832
		}
833
834
		global $frm_vars;
835
		if ( ! isset( $frm_vars['saved_entries'] ) ) {
836
			$frm_vars['saved_entries'] = array();
837
		}
838
839
		$frm_vars['saved_entries'][] = (int) $id;
840
841
		if ( isset( $values['item_meta'] ) ) {
842
			FrmEntryMeta::update_entry_metas( $id, $values['item_meta'] );
843
		}
844
845
		do_action( 'frm_after_update_entry', $id, $new_values['form_id'] );
846
		do_action( 'frm_after_update_entry_' . $new_values['form_id'], $id );
847
	}
848
849
	/**
850
	* Create entry from an XML import
851
	* Certain actions aren't necessary when importing (like saving sub entries, checking for duplicates, etc.)
852
	*
853
	* @since 2.0.16
854
	* @param array $values
855
	* @return int | boolean $entry_id
856
	*/
857
	public static function create_entry_from_xml( $values ) {
858
		$entry_id = self::create_entry( $values, 'xml' );
859
860
		return $entry_id;
861
	}
862
863
	/**
864
	* Update entry from an XML import
865
	* Certain actions aren't necessary when importing (like saving sub entries and modifying other vals)
866
	*
867
	* @since 2.0.16
868
	* @param int $id
869
	* @param array $values
870
	* @return int | boolean $updated
871
	*/
872
	public static function update_entry_from_xml( $id, $values ) {
873
		$updated = self::update_entry( $id, $values, 'xml' );
874
875
		return $updated;
876
	}
877
878
    /**
879
     * @param string $key
880
     * @return int entry_id
881
     */
882
	public static function get_id_by_key( $key ) {
883
        $entry_id = FrmDb::get_var( 'frm_items', array( 'item_key' => sanitize_title( $key ) ) );
884
        return $entry_id;
885
    }
886
}
887