Completed
Push — master ( b3ff26...a88860 )
by Stephanie
02:55
created

FrmEntryMeta   C

Complexity

Total Complexity 71

Size/Duplication

Total Lines 394
Duplicated Lines 2.79 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 11
loc 394
rs 5.5904
c 0
b 0
f 0
wmc 71
lcom 1
cbo 3

15 Methods

Rating   Name   Duplication   Size   Complexity  
B add_entry_meta() 0 29 4
B update_entry_meta() 0 24 3
C update_entry_metas() 0 53 11
A duplicate_entry_metas() 0 8 2
A delete_entry_meta() 0 5 1
A clear_cache() 0 4 1
A get_meta_value() 0 7 3
B get_entry_meta_by_field() 6 32 6
B get_entry_metas_for_field() 0 27 3
B meta_field_query() 5 25 6
A get_entry_meta_info() 0 3 1
B getAll() 0 21 5
A getEntryIds() 0 15 2
C get_ids_query() 0 59 13
D search_entry_metas() 0 41 10

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like FrmEntryMeta often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use FrmEntryMeta, and based on these observations, apply Extract Interface, too.

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