Completed
Push — master ( 5ca997...59227a )
by Stephanie
04:09
created

FrmEntryMeta::duplicate_entry_metas()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 2
dl 0
loc 8
rs 9.4285
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 FrmEntryMeta {
7
8
    /**
9
     * @param string $meta_key
10
     */
11
	public static function add_entry_meta( $entry_id, $field_id, $meta_key = null, $meta_value ) {
0 ignored issues
show
Unused Code introduced by
The parameter $meta_key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
12
        global $wpdb;
13
14
        if ( FrmAppHelper::is_empty_value( $meta_value ) ) {
15
            // don't save blank fields
16
            return 0;
17
        }
18
19
        $new_values = array(
20
			'meta_value'    => is_array( $meta_value ) ? serialize( array_filter( $meta_value, 'FrmAppHelper::is_not_empty_value' ) ) : trim( $meta_value ),
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
21
            'item_id'       => $entry_id,
22
            'field_id'      => $field_id,
23
            'created_at'    => current_time('mysql', 1),
24
        );
25
26
        $new_values = apply_filters('frm_add_entry_meta', $new_values);
27
28
		$query_results = $wpdb->insert( $wpdb->prefix . 'frm_item_metas', $new_values );
29
30
		if ( $query_results ) {
31
			self::clear_cache();
32
			$id = $wpdb->insert_id;
33
		} else {
34
			$id = 0;
35
		}
36
37
        return $id;
38
    }
39
40
    /**
41
     * @param string $meta_key
42
     */
43
	public static function update_entry_meta( $entry_id, $field_id, $meta_key = null, $meta_value ) {
0 ignored issues
show
Unused Code introduced by
The parameter $meta_key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
44
        if ( ! $field_id ) {
45
            return false;
46
        }
47
48
        global $wpdb;
49
50
        $values = $where_values = array( 'item_id' => $entry_id, 'field_id' => $field_id );
51
        $values['meta_value'] = $meta_value;
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
52
        $values = apply_filters('frm_update_entry_meta', $values);
53
		if ( is_array($values['meta_value']) ) {
54
			$values['meta_value'] = array_filter( $values['meta_value'], 'FrmAppHelper::is_not_empty_value' );
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
55
		}
56
        $meta_value = maybe_serialize($values['meta_value']);
57
58
        wp_cache_delete( $entry_id, 'frm_entry');
59
		self::clear_cache();
60
61
		return $wpdb->update( $wpdb->prefix . 'frm_item_metas', array( 'meta_value' => $meta_value ), $where_values );
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
62
    }
63
64
	public static function update_entry_metas( $entry_id, $values ) {
65
        global $wpdb;
66
67
		$prev_values = FrmDb::get_col( $wpdb->prefix . 'frm_item_metas', array( 'item_id' => $entry_id, 'field_id !' => 0 ), 'field_id' );
68
69
        foreach ( $values as $field_id => $meta_value ) {
70
			$field = false;
71
			if ( ! empty( $field_id ) ) {
72
				$field = FrmField::getOne( $field_id );
73
			}
74
75
			// set the value for the file upload field and add new tags (in Pro version)
76
			$meta_value = apply_filters( 'frm_prepare_data_before_db', $meta_value, $field_id, $entry_id, compact( 'field' ) );
77
78
			if ( $prev_values && in_array($field_id, $prev_values) ) {
79
80
				if ( ( is_array( $meta_value ) && empty( $meta_value ) ) || ( ! is_array( $meta_value ) && trim( $meta_value ) == '' ) ) {
81
					// remove blank fields
82
					unset( $values[ $field_id ] );
83
				} else {
84
					// if value exists, then update it
85
					self::update_entry_meta( $entry_id, $field_id, '', $meta_value );
86
				}
87
			} else {
88
				// if value does not exist, then create it
89
				self::add_entry_meta( $entry_id, $field_id, '', $meta_value );
90
			}
91
		}
92
93
        if ( empty($prev_values) ) {
94
            return;
95
        }
96
97
        $prev_values = array_diff($prev_values, array_keys($values));
98
99
        if ( empty($prev_values) ) {
100
            return;
101
        }
102
103
		// prepare the query
104
		$where = array( 'item_id' => $entry_id, 'field_id' => $prev_values );
105
		FrmDb::get_where_clause_and_values( $where );
106
107
        // Delete any leftovers
108
        $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_item_metas ' . $where['where'], $where['values'] ) );
109
		self::clear_cache();
110
    }
111
112
	public static function duplicate_entry_metas( $old_id, $new_id ) {
113
        $metas = self::get_entry_meta_info($old_id);
114
        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...
115
            self::add_entry_meta($new_id, $meta->field_id, null, $meta->meta_value);
116
            unset($meta);
117
        }
118
		self::clear_cache();
119
    }
120
121
	public static function delete_entry_meta( $entry_id, $field_id ) {
122
        global $wpdb;
123
		self::clear_cache();
124
        return $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}frm_item_metas WHERE field_id=%d AND item_id=%d", $field_id, $entry_id));
125
    }
126
127
	/**
128
	 * Clear entry meta caching
129
	 * Called when a meta is added or changed
130
	 *
131
	 * @since 2.0.5
132
	 */
133
	public static function clear_cache() {
134
		FrmAppHelper::cache_delete_group( 'frm_entry_meta' );
135
		FrmAppHelper::cache_delete_group( 'frm_item_meta' );
136
	}
137
138
	/**
139
	 * @since 2.0.9
140
	 */
141
	public static function get_meta_value( $entry, $field_id ) {
142
		if ( isset( $entry->metas ) ) {
143
			return isset( $entry->metas[ $field_id ] ) ? $entry->metas[ $field_id ] : false;
144
		} else {
145
			return self::get_entry_meta_by_field( $entry->id, $field_id );
146
		}
147
	}
148
149
	public static function get_entry_meta_by_field( $entry_id, $field_id ) {
150
        global $wpdb;
151
152
		if ( is_object( $entry_id ) ) {
153
			$entry = $entry_id;
154
			$entry_id = $entry->id;
155
			$cached = $entry;
156
		} else {
157
			$entry_id = (int) $entry_id;
158
			$cached = FrmAppHelper::check_cache( $entry_id, 'frm_entry' );
159
		}
160
161
		if ( $cached && isset( $cached->metas ) && isset( $cached->metas[ $field_id ] ) ) {
162
			$result = $cached->metas[ $field_id ];
163
            return stripslashes_deep($result);
164
        }
165
166
		$get_table = $wpdb->prefix . 'frm_item_metas';
167
		$query = array( 'item_id' => $entry_id );
168 View Code Duplication
        if ( is_numeric($field_id) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
169
			$query['field_id'] = $field_id;
170
        } else {
171
			$get_table .= ' it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_fields fi ON it.field_id=fi.id';
172
			$query['fi.field_key'] = $field_id;
173
        }
174
175
		$result = FrmDb::get_var( $get_table, $query, 'meta_value' );
176
        $result = maybe_unserialize($result);
177
        $result = stripslashes_deep($result);
178
179
        return $result;
180
    }
181
182
	public static function get_entry_metas( $entry_id ) {
183
        _deprecated_function( __FUNCTION__, '1.07.10');
184
185
        global $wpdb;
186
		return FrmDb::get_col( $wpdb->prefix . 'frm_item_metas', array( 'item_id' => $entry_id ), 'meta_value' );
187
    }
188
189
    public static function get_entry_metas_for_field( $field_id, $order = '', $limit = '', $args = array() ) {
190
		$defaults = array( 'value' => false, 'unique' => false, 'stripslashes' => true, 'is_draft' => false );
191
        $args = wp_parse_args( $args, $defaults );
192
193
        $query = array();
194
        self::meta_field_query($field_id, $order, $limit, $args, $query);
195
        $query = implode(' ', $query);
196
197
		$cache_key = 'entry_metas_for_field_' . $field_id . $order . $limit . maybe_serialize( $args );
198
        $values = FrmAppHelper::check_cache($cache_key, 'frm_entry', $query, 'get_col');
199
200
        if ( ! $args['stripslashes'] ) {
201
            return $values;
202
        }
203
204
		foreach ( $values as $k => $v ) {
205
			$values[ $k ] = maybe_unserialize( $v );
206
            unset($k, $v);
207
        }
208
209
        return stripslashes_deep($values);
210
    }
211
212
    /**
213
     * @param string $order
214
     * @param string $limit
215
     */
216
	private static function meta_field_query( $field_id, $order, $limit, $args, array &$query ) {
217
        global $wpdb;
218
        $query[] = 'SELECT';
219
        $query[] = $args['unique'] ? 'DISTINCT(em.meta_value)' : 'em.meta_value';
220
		$query[] = 'FROM ' . $wpdb->prefix . 'frm_item_metas em ';
221
222
        if ( ! $args['is_draft'] ) {
223
			$query[] = 'INNER JOIN ' . $wpdb->prefix . 'frm_items e ON (e.id=em.item_id)';
224
        }
225
226 View Code Duplication
        if ( is_numeric($field_id) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
227
            $query[] = $wpdb->prepare('WHERE em.field_id=%d', $field_id);
228
        } else {
229
			$query[] = $wpdb->prepare( 'LEFT JOIN ' . $wpdb->prefix . 'frm_fields fi ON (em.field_id = fi.id) WHERE fi.field_key=%s', $field_id );
230
        }
231
232
        if ( ! $args['is_draft'] ) {
233
            $query[] = 'AND e.is_draft=0';
234
        }
235
236
        if ( $args['value'] ) {
237
            $query[] = $wpdb->prepare(' AND meta_value=%s', $args['value']);
238
        }
239
        $query[] = $order . $limit;
240
    }
241
242
	public static function get_entry_meta_info( $entry_id ) {
243
		return FrmDb::get_results( 'frm_item_metas', array( 'item_id' => $entry_id ) );
244
    }
245
246
	public static function getAll( $where = array(), $order_by = '', $limit = '', $stripslashes = false ) {
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...
247
        global $wpdb;
248
        $query = 'SELECT it.*, fi.type as field_type, fi.field_key as field_key,
249
            fi.required as required, fi.form_id as field_form_id, fi.name as field_name, fi.options as fi_options
250
			FROM ' . $wpdb->prefix . 'frm_item_metas it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_fields fi ON it.field_id=fi.id' .
251
            FrmAppHelper::prepend_and_or_where(' WHERE ', $where) . $order_by . $limit;
0 ignored issues
show
Documentation introduced by
$where is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
252
253
		$cache_key = 'all_' . maybe_serialize( $where ) . $order_by . $limit;
254
        $results = FrmAppHelper::check_cache($cache_key, 'frm_entry', $query, ($limit == ' LIMIT 1' ? 'get_row' : 'get_results'));
255
256
        if ( ! $results || ! $stripslashes ) {
257
            return $results;
258
        }
259
260
        foreach ( $results as $k => $result ) {
261
			$results[ $k ]->meta_value = stripslashes_deep( maybe_unserialize( $result->meta_value ) );
262
            unset($k, $result);
263
        }
264
265
        return $results;
266
    }
267
268
    public static function getEntryIds( $where = array(), $order_by = '', $limit = '', $unique = true, $args = array() ) {
0 ignored issues
show
Coding Style introduced by
The function name getEntryIds is in camel caps, but expected get_entry_ids instead as per the coding standard.
Loading history...
269
		$defaults = array(
270
			'is_draft' => false,
271
			'user_id'  => '',
272
			'group_by' => '',
273
		);
274
        $args = wp_parse_args($args, $defaults);
275
276
        $query = array();
277
        self::get_ids_query($where, $order_by, $limit, $unique, $args, $query );
278
        $query = implode(' ', $query);
279
280
		$cache_key = 'ids_' . maybe_serialize( $where ) . $order_by . 'l' . $limit . 'u' . $unique . maybe_serialize( $args );
281
        $results = FrmAppHelper::check_cache($cache_key, 'frm_entry', $query, ($limit == ' LIMIT 1' ? 'get_var' : 'get_col'));
282
283
        return $results;
284
    }
285
286
    /**
287
     * @param string|array $where
288
     * @param string $order_by
289
     * @param string $limit
290
     */
291
	private static function get_ids_query( $where, $order_by, $limit, $unique, $args, array &$query ) {
292
        global $wpdb;
293
        $query[] = 'SELECT';
294
295
		$defaults = array( 'return_parent_id' => false );
296
		$args = array_merge( $defaults, $args );
297
298
		if ( $args['return_parent_id'] ) {
299
			$query[] = $unique ? 'DISTINCT(e.parent_item_id)' : 'e.parent_item_id';
300
		} else {
301
			$query[] = $unique ? 'DISTINCT(it.item_id)' : 'it.item_id';
302
		}
303
304
		$query[] = 'FROM ' . $wpdb->prefix . 'frm_item_metas it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_fields fi ON it.field_id=fi.id';
305
306
		$query[] = 'INNER JOIN ' . $wpdb->prefix . 'frm_items e ON (e.id=it.item_id)';
307
        if ( is_array($where) ) {
308
            if ( ! $args['is_draft'] ) {
309
                $where['e.is_draft'] = 0;
310
            } else if ( $args['is_draft'] == 1 ) {
311
                $where['e.is_draft'] = 1;
312
            }
313
314
            if ( ! empty($args['user_id']) ) {
315
                $where['e.user_id'] = $args['user_id'];
316
            }
317
            $query[] = FrmAppHelper::prepend_and_or_where(' WHERE ', $where) . $order_by . $limit;
0 ignored issues
show
Documentation introduced by
$where is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
318
319
			if ( $args['group_by'] ) {
320
				$query[] = ' GROUP BY ' . sanitize_text_field( $args['group_by'] );
321
			}
322
            return;
323
        }
324
325
		$draft_where = $user_where = '';
326
        if ( ! $args['is_draft'] ) {
327
			$draft_where = $wpdb->prepare( ' AND e.is_draft=%d', 0 );
328
        } else if ( $args['is_draft'] == 1 ) {
329
			$draft_where = $wpdb->prepare( ' AND e.is_draft=%d', 1 );
330
        }
331
332
        if ( ! empty($args['user_id']) ) {
333
            $user_where = $wpdb->prepare(' AND e.user_id=%d', $args['user_id']);
334
        }
335
336
        if ( strpos($where, ' GROUP BY ') ) {
337
            // don't inject WHERE filtering after GROUP BY
338
            $parts = explode(' GROUP BY ', $where);
339
            $where = $parts[0];
340
            $where .= $draft_where . $user_where;
341
			$where .= ' GROUP BY ' . $parts[1];
342
        } else {
343
            $where .= $draft_where . $user_where;
344
        }
345
346
		// The query has already been prepared
347
		$query[] = FrmAppHelper::prepend_and_or_where(' WHERE ', $where) . $order_by . $limit;
348
    }
349
350
    public static function search_entry_metas( $search, $field_id = '', $operator ) {
351
		$cache_key = 'search_' . maybe_serialize( $search ) . $field_id . $operator;
352
        $results = wp_cache_get($cache_key, 'frm_entry');
353
        if ( false !== $results ) {
354
            return $results;
355
        }
356
357
        global $wpdb;
358
		if ( is_array( $search ) ) {
359
            $where = '';
360
			foreach ( $search as $field => $value ) {
361
				if ( $value <= 0 || ! in_array( $field, array( 'year', 'month', 'day' ) ) ) {
362
                    continue;
363
                }
364
365
                switch ( $field ) {
366
                    case 'year':
367
						$value = '%' . $value;
368
                    break;
369
                    case 'month':
370
                        $value .= '%';
371
                    break;
372
                    case 'day':
373
						$value = '%' . $value . '%';
374
                }
375
				$where .= $wpdb->prepare(' meta_value ' . $operator . ' %s and', $value );
376
            }
377
            $where .= $wpdb->prepare(' field_id=%d', $field_id);
378
			$query = 'SELECT DISTINCT item_id FROM ' . $wpdb->prefix . 'frm_item_metas' . FrmAppHelper::prepend_and_or_where( ' WHERE ', $where );
379
        } else {
380
			if ( $operator == 'LIKE' ) {
381
                $search = '%' . $search . '%';
382
			}
383
            $query = $wpdb->prepare("SELECT DISTINCT item_id FROM {$wpdb->prefix}frm_item_metas WHERE meta_value {$operator} %s and field_id = %d", $search, $field_id);
384
        }
385
386
        $results = $wpdb->get_col($query, 0);
387
		FrmAppHelper::set_cache( $cache_key, $results, 'frm_entry' );
388
389
        return $results;
390
    }
391
}
392