Completed
Pull Request — master (#54)
by Jamie
03:26
created

FrmEntryMeta::get_entry_metas()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 6
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 = array( 'item_id' => $entry_id, 'field_id' => $field_id );
51
		$where_values = $values;
52
        $values['meta_value'] = $meta_value;
0 ignored issues
show
introduced by
Detected usage of meta_value, possible slow query.
Loading history...
53
        $values = apply_filters('frm_update_entry_meta', $values);
54
		if ( is_array($values['meta_value']) ) {
55
			$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...
56
		}
57
        $meta_value = maybe_serialize($values['meta_value']);
58
59
        wp_cache_delete( $entry_id, 'frm_entry');
60
		self::clear_cache();
61
62
		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...
63
    }
64
65
	public static function update_entry_metas( $entry_id, $values ) {
66
        global $wpdb;
67
68
		$prev_values = FrmDb::get_col( $wpdb->prefix . 'frm_item_metas', array( 'item_id' => $entry_id, 'field_id !' => 0 ), 'field_id' );
69
70
        foreach ( $values as $field_id => $meta_value ) {
71
			$field = false;
72
			if ( ! empty( $field_id ) ) {
73
				$field = FrmField::getOne( $field_id );
74
			}
75
76
			// set the value for the file upload field and add new tags (in Pro version)
77
			$meta_value = apply_filters( 'frm_prepare_data_before_db', $meta_value, $field_id, $entry_id, compact( 'field' ) );
78
79
			if ( $prev_values && in_array($field_id, $prev_values) ) {
80
81
				if ( ( is_array( $meta_value ) && empty( $meta_value ) ) || ( ! is_array( $meta_value ) && trim( $meta_value ) == '' ) ) {
82
					// remove blank fields
83
					unset( $values[ $field_id ] );
84
				} else {
85
					// if value exists, then update it
86
					self::update_entry_meta( $entry_id, $field_id, '', $meta_value );
87
				}
88
			} else {
89
				// if value does not exist, then create it
90
				self::add_entry_meta( $entry_id, $field_id, '', $meta_value );
91
			}
92
		}
93
94
        if ( empty($prev_values) ) {
95
            return;
96
        }
97
98
        $prev_values = array_diff($prev_values, array_keys($values));
99
100
        if ( empty($prev_values) ) {
101
            return;
102
        }
103
104
		// prepare the query
105
		$where = array( 'item_id' => $entry_id, 'field_id' => $prev_values );
106
		FrmDb::get_where_clause_and_values( $where );
107
108
        // Delete any leftovers
109
        $wpdb->query( $wpdb->prepare( 'DELETE FROM ' . $wpdb->prefix . 'frm_item_metas ' . $where['where'], $where['values'] ) );
110
		self::clear_cache();
111
    }
112
113
	public static function duplicate_entry_metas( $old_id, $new_id ) {
114
        $metas = self::get_entry_meta_info($old_id);
115
        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...
116
            self::add_entry_meta($new_id, $meta->field_id, null, $meta->meta_value);
117
            unset($meta);
118
        }
119
		self::clear_cache();
120
    }
121
122
	public static function delete_entry_meta( $entry_id, $field_id ) {
123
        global $wpdb;
124
		self::clear_cache();
125
        return $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}frm_item_metas WHERE field_id=%d AND item_id=%d", $field_id, $entry_id));
126
    }
127
128
	/**
129
	 * Clear entry meta caching
130
	 * Called when a meta is added or changed
131
	 *
132
	 * @since 2.0.5
133
	 */
134
	public static function clear_cache() {
135
		FrmAppHelper::cache_delete_group( 'frm_entry_meta' );
136
		FrmAppHelper::cache_delete_group( 'frm_item_meta' );
137
	}
138
139
	/**
140
	 * @since 2.0.9
141
	 */
142
	public static function get_meta_value( $entry, $field_id ) {
143
		if ( isset( $entry->metas ) ) {
144
			return isset( $entry->metas[ $field_id ] ) ? $entry->metas[ $field_id ] : false;
145
		} else {
146
			return self::get_entry_meta_by_field( $entry->id, $field_id );
147
		}
148
	}
149
150
	public static function get_entry_meta_by_field( $entry_id, $field_id ) {
151
        global $wpdb;
152
153
		if ( is_object( $entry_id ) ) {
154
			$entry = $entry_id;
155
			$entry_id = $entry->id;
156
			$cached = $entry;
157
		} else {
158
			$entry_id = (int) $entry_id;
159
			$cached = FrmAppHelper::check_cache( $entry_id, 'frm_entry' );
160
		}
161
162
		if ( $cached && isset( $cached->metas ) && isset( $cached->metas[ $field_id ] ) ) {
163
			$result = $cached->metas[ $field_id ];
164
            return stripslashes_deep($result);
165
        }
166
167
		$get_table = $wpdb->prefix . 'frm_item_metas';
168
		$query = array( 'item_id' => $entry_id );
169 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...
170
			$query['field_id'] = $field_id;
171
        } else {
172
			$get_table .= ' it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_fields fi ON it.field_id=fi.id';
173
			$query['fi.field_key'] = $field_id;
174
        }
175
176
		$result = FrmDb::get_var( $get_table, $query, 'meta_value' );
177
        $result = maybe_unserialize($result);
178
        $result = stripslashes_deep($result);
179
180
        return $result;
181
    }
182
183
    public static function get_entry_metas_for_field( $field_id, $order = '', $limit = '', $args = array() ) {
184
		$defaults = array( 'value' => false, 'unique' => false, 'stripslashes' => true, 'is_draft' => false );
185
        $args = wp_parse_args( $args, $defaults );
186
187
        $query = array();
188
        self::meta_field_query($field_id, $order, $limit, $args, $query);
189
        $query = implode(' ', $query);
190
191
		$cache_key = 'entry_metas_for_field_' . $field_id . $order . $limit . maybe_serialize( $args );
192
        $values = FrmAppHelper::check_cache($cache_key, 'frm_entry', $query, 'get_col');
193
194
        if ( ! $args['stripslashes'] ) {
195
            return $values;
196
        }
197
198
		foreach ( $values as $k => $v ) {
199
			$values[ $k ] = maybe_unserialize( $v );
200
            unset($k, $v);
201
        }
202
203
        return stripslashes_deep($values);
204
    }
205
206
    /**
207
     * @param string $order
208
     * @param string $limit
209
     */
210
	private static function meta_field_query( $field_id, $order, $limit, $args, array &$query ) {
211
        global $wpdb;
212
        $query[] = 'SELECT';
213
        $query[] = $args['unique'] ? 'DISTINCT(em.meta_value)' : 'em.meta_value';
214
		$query[] = 'FROM ' . $wpdb->prefix . 'frm_item_metas em ';
215
216
        if ( ! $args['is_draft'] ) {
217
			$query[] = 'INNER JOIN ' . $wpdb->prefix . 'frm_items e ON (e.id=em.item_id)';
218
        }
219
220 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...
221
            $query[] = $wpdb->prepare('WHERE em.field_id=%d', $field_id);
222
        } else {
223
			$query[] = $wpdb->prepare( 'LEFT JOIN ' . $wpdb->prefix . 'frm_fields fi ON (em.field_id = fi.id) WHERE fi.field_key=%s', $field_id );
224
        }
225
226
        if ( ! $args['is_draft'] ) {
227
            $query[] = 'AND e.is_draft=0';
228
        }
229
230
        if ( $args['value'] ) {
231
            $query[] = $wpdb->prepare(' AND meta_value=%s', $args['value']);
232
        }
233
        $query[] = $order . $limit;
234
    }
235
236
	public static function get_entry_meta_info( $entry_id ) {
237
		return FrmDb::get_results( 'frm_item_metas', array( 'item_id' => $entry_id ) );
238
    }
239
240
	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...
241
        global $wpdb;
242
        $query = 'SELECT it.*, fi.type as field_type, fi.field_key as field_key,
243
            fi.required as required, fi.form_id as field_form_id, fi.name as field_name, fi.options as fi_options
244
			FROM ' . $wpdb->prefix . 'frm_item_metas it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_fields fi ON it.field_id=fi.id' .
245
            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...
246
247
		$cache_key = 'all_' . maybe_serialize( $where ) . $order_by . $limit;
248
        $results = FrmAppHelper::check_cache($cache_key, 'frm_entry', $query, ($limit == ' LIMIT 1' ? 'get_row' : 'get_results'));
249
250
        if ( ! $results || ! $stripslashes ) {
251
            return $results;
252
        }
253
254
        foreach ( $results as $k => $result ) {
255
			$results[ $k ]->meta_value = stripslashes_deep( maybe_unserialize( $result->meta_value ) );
256
            unset($k, $result);
257
        }
258
259
        return $results;
260
    }
261
262
    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...
263
		$defaults = array(
264
			'is_draft' => false,
265
			'user_id'  => '',
266
			'group_by' => '',
267
		);
268
        $args = wp_parse_args($args, $defaults);
269
270
        $query = array();
271
        self::get_ids_query($where, $order_by, $limit, $unique, $args, $query );
272
        $query = implode(' ', $query);
273
274
		$cache_key = 'ids_' . maybe_serialize( $where ) . $order_by . 'l' . $limit . 'u' . $unique . maybe_serialize( $args );
275
        $results = FrmAppHelper::check_cache($cache_key, 'frm_entry', $query, ($limit == ' LIMIT 1' ? 'get_var' : 'get_col'));
276
277
        return $results;
278
    }
279
280
    /**
281
     * @param string|array $where
282
     * @param string $order_by
283
     * @param string $limit
284
     */
285
	private static function get_ids_query( $where, $order_by, $limit, $unique, $args, array &$query ) {
286
        global $wpdb;
287
        $query[] = 'SELECT';
288
289
		$defaults = array( 'return_parent_id' => false );
290
		$args = array_merge( $defaults, $args );
291
292
		if ( $args['return_parent_id'] ) {
293
			$query[] = $unique ? 'DISTINCT(e.parent_item_id)' : 'e.parent_item_id';
294
		} else {
295
			$query[] = $unique ? 'DISTINCT(it.item_id)' : 'it.item_id';
296
		}
297
298
		$query[] = 'FROM ' . $wpdb->prefix . 'frm_item_metas it LEFT OUTER JOIN ' . $wpdb->prefix . 'frm_fields fi ON it.field_id=fi.id';
299
300
		$query[] = 'INNER JOIN ' . $wpdb->prefix . 'frm_items e ON (e.id=it.item_id)';
301
        if ( is_array($where) ) {
302
            if ( ! $args['is_draft'] ) {
303
                $where['e.is_draft'] = 0;
304
            } else if ( $args['is_draft'] == 1 ) {
305
                $where['e.is_draft'] = 1;
306
            }
307
308
            if ( ! empty($args['user_id']) ) {
309
                $where['e.user_id'] = $args['user_id'];
310
            }
311
            $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...
312
313
			if ( $args['group_by'] ) {
314
				$query[] = ' GROUP BY ' . sanitize_text_field( $args['group_by'] );
315
			}
316
            return;
317
        }
318
319
		$draft_where = '';
320
		$user_where = '';
321
        if ( ! $args['is_draft'] ) {
322
			$draft_where = $wpdb->prepare( ' AND e.is_draft=%d', 0 );
323
        } else if ( $args['is_draft'] == 1 ) {
324
			$draft_where = $wpdb->prepare( ' AND e.is_draft=%d', 1 );
325
        }
326
327
        if ( ! empty($args['user_id']) ) {
328
            $user_where = $wpdb->prepare(' AND e.user_id=%d', $args['user_id']);
329
        }
330
331
        if ( strpos($where, ' GROUP BY ') ) {
332
            // don't inject WHERE filtering after GROUP BY
333
            $parts = explode(' GROUP BY ', $where);
334
            $where = $parts[0];
335
            $where .= $draft_where . $user_where;
336
			$where .= ' GROUP BY ' . $parts[1];
337
        } else {
338
            $where .= $draft_where . $user_where;
339
        }
340
341
		// The query has already been prepared
342
		$query[] = FrmAppHelper::prepend_and_or_where(' WHERE ', $where) . $order_by . $limit;
343
    }
344
345
    public static function search_entry_metas( $search, $field_id = '', $operator ) {
346
		$cache_key = 'search_' . maybe_serialize( $search ) . $field_id . $operator;
347
        $results = wp_cache_get($cache_key, 'frm_entry');
348
        if ( false !== $results ) {
349
            return $results;
350
        }
351
352
        global $wpdb;
353
		if ( is_array( $search ) ) {
354
            $where = '';
355
			foreach ( $search as $field => $value ) {
356
				if ( $value <= 0 || ! in_array( $field, array( 'year', 'month', 'day' ) ) ) {
357
                    continue;
358
                }
359
360
                switch ( $field ) {
361
                    case 'year':
362
						$value = '%' . $value;
363
                    break;
364
                    case 'month':
365
                        $value .= '%';
366
                    break;
367
                    case 'day':
368
						$value = '%' . $value . '%';
369
                }
370
				$where .= $wpdb->prepare(' meta_value ' . $operator . ' %s and', $value );
371
            }
372
            $where .= $wpdb->prepare(' field_id=%d', $field_id);
373
			$query = 'SELECT DISTINCT item_id FROM ' . $wpdb->prefix . 'frm_item_metas' . FrmAppHelper::prepend_and_or_where( ' WHERE ', $where );
374
        } else {
375
			if ( $operator == 'LIKE' ) {
376
                $search = '%' . $search . '%';
377
			}
378
            $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);
379
        }
380
381
        $results = $wpdb->get_col($query, 0);
382
		FrmAppHelper::set_cache( $cache_key, $results, 'frm_entry' );
383
384
        return $results;
385
    }
386
}
387