Completed
Push — develop ( 7592b8...3eb7c5 )
by Zack
14:44
created

GravityView_Field_Address::field_options()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 13
nc 3
nop 5
dl 0
loc 23
ccs 0
cts 11
cp 0
crap 12
rs 9.0856
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 11 and the first side effect is on line 278.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * @file class-gravityview-field-address.php
4
 * @package GravityView
5
 * @subpackage includes\fields
6
 */
7
8
/**
9
 * Add custom options for address fields
10
 */
11
class GravityView_Field_Address extends GravityView_Field {
12
13
	var $name = 'address';
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $name.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
14
15
	var $group = 'advanced';
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $group.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
16
17
	var $is_numeric = false;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $is_numeric.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
18
19
	var $is_searchable = true;
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $is_searchable.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
20
21
	var $search_operators = array( 'is', 'isnot', 'contains' );
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $search_operators.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
22
23
	var $_gf_field_class_name = 'GF_Field_Address';
0 ignored issues
show
Coding Style introduced by
The visibility should be declared for property $_gf_field_class_name.

The PSR-2 coding standard requires that all properties in a class have their visibility explicitly declared. If you declare a property using

class A {
    var $property;
}

the property is implicitly global.

To learn more about the PSR-2, please see the PHP-FIG site on the PSR-2.

Loading history...
24
25
	public function __construct() {
26
		$this->label = esc_html__( 'Address', 'gravityview' );
27
28
		$this->add_hooks();
29
30
		parent::__construct();
31
	}
32
33
	/**
34
	 * Add filters for this field type
35
	 *
36
	 * @since 1.19.2
37
	 *
38
	 * @return void
39
	 */
40
	private function add_hooks() {
41
		add_filter( 'gravityview/extension/search/input_type', array( $this, 'search_bar_input_type' ), 10, 3 );
42
		add_filter( 'gravityview/search/input_types', array( $this, 'input_types' ) );
43
		add_filter( 'gravityview_widget_search_filters', array( $this, 'search_field_filter' ), 10, 3 );
44
	}
45
46
	/**
47
	 * Dynamically add choices to the address field dropdowns, if any
48
	 *
49
	 * @since 1.19.2
50
	 *
51
	 * @param array $search_fields Array of search filters with `key`, `label`, `value`, `type` keys
52
	 * @param GravityView_Widget_Search $widget Current widget object
53
	 * @param array $widget_args Args passed to this method. {@since 1.8}
54
	 *
55
	 * @return array If the search field GF Field type is `address`, and there are choices to add, adds them and changes the input type. Otherwise, sets the input to text.
56
	 */
57
	public function search_field_filter( $search_fields, $widget, $widget_args ) {
0 ignored issues
show
Unused Code introduced by
The parameter $widget 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...
Unused Code introduced by
The parameter $widget_args 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...
58
59
		foreach ( $search_fields as & $search_field ) {
60
61
			if ( 'address' === rgar( $search_field, 'type' ) ) {
62
63
				$field_id = intval( floor( $search_field['key'] ) );
64
				$input_id = gravityview_get_input_id_from_id( $search_field['key'] );
65
				$form = GravityView_View::getInstance()->getForm();
66
67
				/** @var GF_Field_Address $address_field */
68
				$address_field = GFFormsModel::get_field( $form, $field_id );
69
70
				$choices = array();
71
72
				$method_name = 'get_choices_' . self::get_input_type_from_input_id( $input_id );
73
				if( method_exists( $this, $method_name ) ) {
74
					/**
75
					 * @uses GravityView_Field_Address::get_choices_country()
76
					 * @uses GravityView_Field_Address::get_choices_state()
77
					 */
78
					$choices = $this->{$method_name}( $address_field );
79
				}
80
81
				if( ! empty( $choices ) ) {
82
					$search_field['choices'] = $choices;
83
					$search_field['type'] = rgar( $search_field, 'input');
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
84
				} else {
85
					$search_field['type'] = 'text';
86
					$search_field['input'] = 'input_text';
87
				}
88
			}
89
		}
90
91
		return $search_fields;
92
	}
93
94
	/**
95
	 * Get array of countries to use for the search choices
96
	 *
97
	 * @since 1.19.2
98
	 *
99
	 * @see GF_Field_Address::get_countries()
100
	 *
101
	 * @param GF_Field_Address $address_field
102
	 *
103
	 * @return array Array of countries with `value` and `text` keys as the name of the country
104
	 */
105
	private function get_choices_country( $address_field ) {
106
107
		$countries = $address_field->get_countries();
108
109
		$country_choices = array();
110
111
		foreach ( $countries as $key => $country ) {
112
			$country_choices[] = array(
113
				'value' => $country,
114
				'text' => $country,
115
			);
116
		}
117
118
		return $country_choices;
119
	}
120
121
	/**
122
	 * Get array of states to use for the search choices
123
	 *
124
	 * @since 1.19.2
125
	 *
126
	 * @uses GF_Field_Address::get_us_states()
127
	 * @uses GF_Field_Address::get_us_state_code()
128
	 * @uses GF_Field_Address::get_canadian_provinces()
129
	 *
130
	 * @param GF_Field_Address $address_field
131
	 *
132
	 * @return array Array of countries with `value` and `text` keys as the name of the country
133
	 */
134
	private function get_choices_state( $address_field ) {
135
136
		$address_type = empty( $address_field->addressType ) ? $address_field->get_default_address_type( $form['id'] ) : $address_field->addressType;
0 ignored issues
show
Bug introduced by
The variable $form does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
137
138
		$state_choices = array();
139
140
		switch ( $address_type ) {
141
			case 'us':
142
				$states = GFCommon::get_us_states();
143
				break;
144
			case 'canadian':
145
				$states = GFCommon::get_canadian_provinces();
146
				break;
147
			default:
148
				$states = empty( $address_types[ $address_type ]['states'] ) ? array() : $address_types[ $address_type ]['states'];
0 ignored issues
show
Bug introduced by
The variable $address_types does not exist. Did you mean $address_type?

This check looks for variables that are accessed but have not been defined. It raises an issue if it finds another variable that has a similar name.

The variable may have been renamed without also renaming all references.

Loading history...
149
				break;
150
		}
151
152
		foreach ( $states as $key => $state ) {
153
			$state_choices[] = array(
154
				'value' => $state,
155
				'text' => $state,
156
			);
157
		}
158
159
		return $state_choices;
160
	}
161
162
	/**
163
	 * Add the input types available for each custom search field type
164
	 *
165
	 * @since 1.19.2
166
	 *
167
	 * @param array $input_types Array of input types as the keys (`select`, `radio`, `multiselect`, `input_text`) with a string or array of supported inputs as values
168
	 *
169
	 * @return array $input_types array, but
170
	 */
171
	public function input_types( $input_types ) {
172
173
		// Use the same inputs as the "text" input type allows
174
		$text_inputs = rgar( $input_types, 'text' );
175
176
		$input_types['street'] = $text_inputs;
177
		$input_types['street2'] = $text_inputs;
178
		$input_types['city'] = $text_inputs;
179
180
		$input_types['state'] = array( 'select', 'radio', 'link' ) + $text_inputs;
181
		$input_types['zip'] = array( 'input_text' );
182
		$input_types['country'] = array( 'select', 'radio', 'link' ) + $text_inputs;
183
184
		return $input_types;
185
	}
186
187
	/**
188
	 * Converts the custom input type (address) into the selected type
189
	 *
190
	 * @since 1.19.2
191
	 *
192
	 * @param string $input_type Assign an input type according to the form field type. Defaults: `boolean`, `multi`, `select`, `date`, `text`
193
	 * @param string $field_type Gravity Forms field type (also the `name` parameter of GravityView_Field classes)
194
	 * @param string|int|float $field_id ID of the field being processed
195
	 *
196
	 * @return string If the field ID matches an address field input, return those options {@see GravityView_Field_Address::input_types() }. Otherwise, original value is used.
197
	 */
198
	public function search_bar_input_type( $input_type, $field_type, $field_id ) {
199
200
		// Is this search field for an input (eg: 4.2) or the whole address field (eg: 4)?
201
		$input_id = gravityview_get_input_id_from_id( $field_id );
202
203
		if( 'address' === $field_type && $input_id ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $input_id of type false|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
204
205
			// If the input ID matches an expected address input, set to that. Otherwise, keep existing input type.
206
			if( $address_field_name = self::get_input_type_from_input_id( $input_id ) ) {
207
				$input_type = $address_field_name;
208
			}
209
		}
210
211
		return $input_type;
212
	}
213
214
	/**
215
	 * Get a name for the input based on the input ID
216
	 *
217
	 * @since 1.19.2
218
	 *
219
	 * @param int $input_id ID of the specific input for the address field
220
	 *
221
	 * @return false|string If the input ID matches a known address field input, returns a name for that input ("city", or "country"). Otherwise, returns false.
222
	 */
223
	private static function get_input_type_from_input_id( $input_id ) {
224
225
		$input_type = false;
226
227
		switch ( $input_id ) {
228
			case 1:
229
				$input_type = 'street';
230
				break;
231
			case 2:
232
				$input_type = 'street2';
233
				break;
234
			case 3:
235
				$input_type = 'city';
236
				break;
237
				break;
0 ignored issues
show
Unused Code introduced by
break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
238
			case 4:
239
				$input_type = 'state';
240
				break;
241
			case 5:
242
				$input_type = 'zip';
243
				break;
244
			case 6:
245
				$input_type = 'country';
246
				break;
247
		}
248
249
		return $input_type;
250
	}
251
252
	function field_options( $field_options, $template_id = '', $field_id = '', $context = '', $input_type = '' ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
253
254
		// If this is NOT the full address field, return default options.
255
		if( floor( $field_id ) !== floatval( $field_id ) ) {
256
			return $field_options;
257
		}
258
259
		if( 'edit' === $context ) {
260
			return $field_options;
261
		}
262
263
		$add_options = array();
264
265
		$add_options['show_map_link'] = array(
266
			'type' => 'checkbox',
267
			'label' => __( 'Show Map Link:', 'gravityview' ),
268
			'desc' => __('Display a "Map It" link below the address', 'gravityview'),
0 ignored issues
show
Coding Style introduced by
Expected 1 spaces after opening bracket; 0 found
Loading history...
Coding Style introduced by
Expected 1 spaces before closing bracket; 0 found
Loading history...
269
			'value' => true,
270
			'merge_tags' => false,
271
		);
272
273
		return $add_options + $field_options;
274
	}
275
276
}
277
278
new GravityView_Field_Address;
279