Completed
Push — develop ( 578953...555ad7 )
by Zack
26:20 queued 13:08
created

View::get_joined_forms()   B

Complexity

Conditions 11
Paths 10

Size

Total Lines 41

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 14.8983

Importance

Changes 0
Metric Value
cc 11
nc 10
nop 1
dl 0
loc 41
ccs 15
cts 22
cp 0.6818
crap 14.8983
rs 7.3166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace GV;
3
4
/** If this file is called directly, abort. */
5
if ( ! defined( 'GRAVITYVIEW_DIR' ) ) {
6
	die();
7
}
8
9
/**
10
 * The default GravityView View class.
11
 *
12
 * Houses all base View functionality.
13
 *
14
 * Can be accessed as an array for old compatibility's sake
15
 *  in line with the elements inside the \GravityView_View_Data::$views array.
16
 */
17
class View implements \ArrayAccess {
18
19
	/**
20
	 * @var \WP_Post The backing post instance.
21
	 */
22
	private $post;
23
24
	/**
25
	 * @var \GV\View_Settings The settings.
26
	 *
27
	 * @api
28
	 * @since 2.0
29
	 */
30
	public $settings;
31
32
	/**
33
	 * @var \GV\Widget_Collection The widets attached here.
34
	 *
35
	 * @api
36
	 * @since 2.0
37
	 */
38
	public $widgets;
39
40
	/**
41
	 * @var \GV\GF_Form|\GV\Form The backing form for this view.
42
	 *
43
	 * Contains the form that is sourced for entries in this view.
44
	 *
45
	 * @api
46
	 * @since 2.0
47
	 */
48
	public $form;
49
50
	/**
51
	 * @var \GV\Field_Collection The fields for this view.
52
	 *
53
	 * Contains all the fields that are attached to this view.
54
	 *
55
	 * @api
56
	 * @since 2.0
57
	 */
58
	public $fields;
59
60
	/**
61
	 * @var array
62
	 *
63
	 * Internal static cache for gets, and whatnot.
64
	 * This is not persistent, resets across requests.
65
66
	 * @internal
67
	 */
68
	private static $cache = array();
69
70
	/**
71
	 * @var \GV\Join[] The joins for all sources in this view.
72
	 *
73
	 * @api
74
	 * @since 2.0.1
75
	 */
76
	public $joins = array();
77
78
	/**
79
	 * @var \GV\Field[][] The unions for all sources in this view.
80
	 *                    An array of fields grouped by form_id keyed by
81
	 *                    main field_id:
82
	 *
83
	 *                    array(
84
	 *                        $form_id => array(
85
	 *                            $field_id => $field,
86
	 *                            $field_id => $field,
87
	 *                        )
88
	 *                    )
89
	 *
90
	 * @api
91
	 * @since 2.2.2
92
	 */
93
	public $unions = array();
94
95
	/**
96
	 * The constructor.
97
	 */
98 171
	public function __construct() {
99 171
		$this->settings = new View_Settings();
100 171
		$this->fields = new Field_Collection();
101 171
		$this->widgets = new Widget_Collection();
102 171
	}
103
104
	/**
105
	 * Register the gravityview WordPress Custom Post Type.
106
	 *
107
	 * @internal
108
	 * @return void
109
	 */
110
	public static function register_post_type() {
111
112
		/** Register only once */
113
		if ( post_type_exists( 'gravityview' ) ) {
114
			return;
115
		}
116
117
		/**
118
		 * @filter `gravityview_is_hierarchical` Make GravityView Views hierarchical by returning TRUE
119
		 * This will allow for Views to be nested with Parents and also allows for menu order to be set in the Page Attributes metabox
120
		 * @since 1.13
121
		 * @param boolean $is_hierarchical Default: false
122
		 */
123
		$is_hierarchical = (bool)apply_filters( 'gravityview_is_hierarchical', false );
124
125
		$supports = array( 'title', 'revisions' );
126
127
		if ( $is_hierarchical ) {
128
			$supports[] = 'page-attributes';
129
		}
130
131
		/**
132
		 * @filter  `gravityview_post_type_supports` Modify post type support values for `gravityview` post type
133
		 * @see add_post_type_support()
134
		 * @since 1.15.2
135
		 * @param array $supports Array of features associated with a functional area of the edit screen. Default: 'title', 'revisions'. If $is_hierarchical, also 'page-attributes'
136
		 * @param[in] boolean $is_hierarchical Do Views support parent/child relationships? See `gravityview_is_hierarchical` filter.
137
		 */
138
		$supports = apply_filters( 'gravityview_post_type_support', $supports, $is_hierarchical );
139
140
		/** Register Custom Post Type - gravityview */
141
		$labels = array(
142
			'name'                => _x( 'Views', 'Post Type General Name', 'gravityview' ),
143
			'singular_name'       => _x( 'View', 'Post Type Singular Name', 'gravityview' ),
144
			'menu_name'           => _x( 'Views', 'Menu name', 'gravityview' ),
145
			'parent_item_colon'   => __( 'Parent View:', 'gravityview' ),
146
			'all_items'           => __( 'All Views', 'gravityview' ),
147
			'view_item'           => _x( 'View', 'View Item', 'gravityview' ),
148
			'add_new_item'        => __( 'Add New View', 'gravityview' ),
149
			'add_new'             => __( 'New View', 'gravityview' ),
150
			'edit_item'           => __( 'Edit View', 'gravityview' ),
151
			'update_item'         => __( 'Update View', 'gravityview' ),
152
			'search_items'        => __( 'Search Views', 'gravityview' ),
153
			'not_found'           => \GravityView_Admin::no_views_text(),
154
			'not_found_in_trash'  => __( 'No Views found in Trash', 'gravityview' ),
155
			'filter_items_list'     => __( 'Filter Views list', 'gravityview' ),
156
			'items_list_navigation' => __( 'Views list navigation', 'gravityview' ),
157
			'items_list'            => __( 'Views list', 'gravityview' ),
158
			'view_items'            => __( 'See Views', 'gravityview' ),
159
			'attributes'            => __( 'View Attributes', 'gravityview' ),
160
		);
161
		$args = array(
162
			'label'               => __( 'view', 'gravityview' ),
163
			'description'         => __( 'Create views based on a Gravity Forms form', 'gravityview' ),
164
			'labels'              => $labels,
165
			'supports'            => $supports,
166
			'hierarchical'        => $is_hierarchical,
167
			/**
168
			 * @filter `gravityview_direct_access` Should Views be directly accessible, or only visible using the shortcode?
169
			 * @see https://codex.wordpress.org/Function_Reference/register_post_type#public
170
			 * @since 1.15.2
171
			 * @param[in,out] boolean `true`: allow Views to be accessible directly. `false`: Only allow Views to be embedded via shortcode. Default: `true`
172
			 * @param int $view_id The ID of the View currently being requested. `0` for general setting
173
			 */
174
			'public'              => apply_filters( 'gravityview_direct_access', gravityview()->plugin->is_compatible(), 0 ),
175
			'show_ui'             => gravityview()->plugin->is_compatible(),
176
			'show_in_menu'        => gravityview()->plugin->is_compatible(),
177
			'show_in_nav_menus'   => true,
178
			'show_in_admin_bar'   => true,
179
			'menu_position'       => 17,
180
			'menu_icon'           => '',
181
			'can_export'          => true,
182
			/**
183
			 * @filter `gravityview_has_archive` Enable Custom Post Type archive?
184
			 * @since 1.7.3
185
			 * @param boolean False: don't have frontend archive; True: yes, have archive. Default: false
186
			 */
187
			'has_archive'         => apply_filters( 'gravityview_has_archive', false ),
188
			'exclude_from_search' => true,
189
			'rewrite'             => array(
190
				/**
191
				 * @filter `gravityview_slug` Modify the url part for a View.
192
				 * @see https://docs.gravityview.co/article/62-changing-the-view-slug
193
				 * @param string $slug The slug shown in the URL
194
				 */
195
				'slug' => apply_filters( 'gravityview_slug', 'view' ),
196
197
				/**
198
				 * @filter `gravityview/post_type/with_front` Should the permalink structure
199
				 *  be prepended with the front base.
200
				 *  (example: if your permalink structure is /blog/, then your links will be: false->/view/, true->/blog/view/).
201
				 *  Defaults to true.
202
				 * @see https://codex.wordpress.org/Function_Reference/register_post_type
203
				 * @since 2.0
204
				 * @param bool $with_front
205
				 */
206
				'with_front' => apply_filters( 'gravityview/post_type/with_front', true ),
207
			),
208
			'capability_type'     => 'gravityview',
209
			'map_meta_cap'        => true,
210
		);
211
212
		register_post_type( 'gravityview', $args );
213
	}
214
215
	/**
216
	 * Add extra rewrite endpoints.
217
	 *
218
	 * @return void
219
	 */
220 1
	public static function add_rewrite_endpoint() {
221
		/**
222
		 * CSV.
223
		 */
224
		global $wp_rewrite;
225
226
		$slug = apply_filters( 'gravityview_slug', 'view' );
227
		$rule = array( sprintf( '%s/([^/]+)/csv/?', $slug ), 'index.php?gravityview=$matches[1]&csv=1', 'top' );
228
229 1
		add_filter( 'query_vars', function( $query_vars ) { 
230 1
			$query_vars[] = 'csv';
231 1
			return $query_vars;
232
		} );
233
234
		if ( ! isset( $wp_rewrite->extra_rules_top[ $rule[0] ] ) ) {
235
			call_user_func_array( 'add_rewrite_rule', $rule );
236
		}
237
	}
238
239
	/**
240
	 * A renderer filter for the View post type content.
241
	 *
242
	 * @param string $content Should be empty, as we don't store anything there.
243
	 *
244
	 * @return string $content The view content as output by the renderers.
245
	 */
246 11
	public static function content( $content ) {
247 11
		$request = gravityview()->request;
248
249
		// Plugins may run through the content in the header. WP SEO does this for its OpenGraph functionality.
250 11
		if ( ! defined( 'DOING_GRAVITYVIEW_TESTS' ) ) {
251
			if ( ! did_action( 'loop_start' ) ) {
252
				gravityview()->log->debug( 'Not processing yet: loop_start hasn\'t run yet. Current action: {action}', array( 'action' => current_filter() ) );
253
				return $content;
254
			}
255
256
			//	We don't want this filter to run infinite loop on any post content fields
257
			remove_filter( 'the_content', array( __CLASS__, __METHOD__ ) );
258
		}
259
260
		/**
261
		 * This is not a View. Bail.
262
		 *
263
		 * Shortcodes and oEmbeds and whatnot will be handled
264
		 *  elsewhere.
265
		 */
266 11
		if ( ! $view = $request->is_view() ) {
267 5
			return $content;
268
		}
269
270
		/**
271
		 * Check permissions.
272
		 */
273 6
		while ( $error = $view->can_render( null, $request ) ) {
274 6
			if ( ! is_wp_error( $error ) )
275 6
				break;
276
277 1
			switch ( str_replace( 'gravityview/', '', $error->get_error_code() ) ) {
278 1
				case 'post_password_required':
279 1
					return get_the_password_form( $view->ID );
280 1
				case 'no_form_attached':
281
282
					gravityview()->log->error( 'View #{view_id} cannot render: {error_code} {error_message}', array( 'error_code' => $error->get_error_code(), 'error_message' => $error->get_error_message() ) );
283
284
					/**
285
					 * This View has no data source. There's nothing to show really.
286
					 * ...apart from a nice message if the user can do anything about it.
287
					 */
288
					if ( \GVCommon::has_cap( array( 'edit_gravityviews', 'edit_gravityview' ), $view->ID ) ) {
289
						return __( sprintf( 'This View is not configured properly. Start by <a href="%s">selecting a form</a>.', esc_url( get_edit_post_link( $view->ID, false ) ) ), 'gravityview' );
290
					}
291
					break;
292 1
				case 'in_trash':
293
294
					if ( \GVCommon::has_cap( array( 'edit_gravityviews', 'edit_gravityview' ), $view->ID ) ) {
295
						return __( sprintf( 'This View is in the Trash. You can <a href="%s">restore the View here</a>.', esc_url( get_edit_post_link( $view->ID, false ) ) ), 'gravityview' );
296
					}
297
298
					return ''; // Do not show
299
					break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
300 1
				case 'no_direct_access':
301 1
				case 'embed_only':
302 1
				case 'not_public':
303
				default:
304 1
					gravityview()->log->notice( 'View #{view_id} cannot render: {error_code} {error_message}', array( 'error_code' => $error->get_error_code(), 'error_message' => $error->get_error_message() ) );
305 1
					return __( 'You are not allowed to view this content.', 'gravityview' );
306
			}
307
308
			return $content;
309
		}
310
311 6
		$is_admin_and_can_view = $view->settings->get( 'admin_show_all_statuses' ) && \GVCommon::has_cap('gravityview_moderate_entries', $view->ID );
312
313
		/**
314
		 * Editing a single entry.
315
		 */
316 6
		if ( $entry = $request->is_edit_entry( $view->form ? $view->form->ID : 0 ) ) {
317
			if ( $entry['status'] != 'active' ) {
318
				gravityview()->log->notice( 'Entry ID #{entry_id} is not active', array( 'entry_id' => $entry->ID ) );
319
				return __( 'You are not allowed to view this content.', 'gravityview' );
320
			}
321
322
			if ( apply_filters( 'gravityview_custom_entry_slug', false ) && $entry->slug != get_query_var( \GV\Entry::get_endpoint_name() ) ) {
323
				gravityview()->log->error( 'Entry ID #{entry_id} was accessed by a bad slug', array( 'entry_id' => $entry->ID ) );
324
				return __( 'You are not allowed to view this content.', 'gravityview' );
325
			}
326
327
			if ( $view->settings->get( 'show_only_approved' ) && ! $is_admin_and_can_view ) {
328
				if ( ! \GravityView_Entry_Approval_Status::is_approved( gform_get_meta( $entry->ID, \GravityView_Entry_Approval::meta_key ) )  ) {
329
					gravityview()->log->error( 'Entry ID #{entry_id} is not approved for viewing', array( 'entry_id' => $entry->ID ) );
330
					return __( 'You are not allowed to view this content.', 'gravityview' );
331
				}
332
			}
333
334
			$renderer = new Edit_Entry_Renderer();
335
			return $renderer->render( $entry, $view, $request );
336
337
		/**
338
		 * Viewing a single entry.
339
		 */
340 6
		} else if ( $entry = $request->is_entry( $view->form ? $view->form->ID : 0 ) ) {
341
342 2
			$entryset = $entry->is_multi() ? $entry->entries : array( $entry );
343
344 2
			$custom_slug = apply_filters( 'gravityview_custom_entry_slug', false );
345 2
			$ids = explode( ',', get_query_var( \GV\Entry::get_endpoint_name() ) );
346
347 2
			$show_only_approved = $view->settings->get( 'show_only_approved' );
348
349 2
			foreach ( $entryset as $e ) {
350
351 2
				if ( 'active' !== $e['status'] ) {
352 1
					gravityview()->log->notice( 'Entry ID #{entry_id} is not active', array( 'entry_id' => $e->ID ) );
353 1
					return __( 'You are not allowed to view this content.', 'gravityview' );
354
				}
355
356 2
				if ( $custom_slug && ! in_array( $e->slug, $ids ) ) {
357 1
					gravityview()->log->error( 'Entry ID #{entry_id} was accessed by a bad slug', array( 'entry_id' => $e->ID ) );
358 1
					return __( 'You are not allowed to view this content.', 'gravityview' );
359
				}
360
361 2
				if ( $show_only_approved && ! $is_admin_and_can_view ) {
362 1
					if ( ! \GravityView_Entry_Approval_Status::is_approved( gform_get_meta( $e->ID, \GravityView_Entry_Approval::meta_key ) )  ) {
363 1
						gravityview()->log->error( 'Entry ID #{entry_id} is not approved for viewing', array( 'entry_id' => $e->ID ) );
364 1
						return __( 'You are not allowed to view this content.', 'gravityview' );
365
					}
366
				}
367
368 2
				$error = \GVCommon::check_entry_display( $e->as_entry(), $view );
369
370 2
				if ( is_wp_error( $error ) ) {
371 1
					gravityview()->log->error( 'Entry ID #{entry_id} is not approved for viewing: {message}', array( 'entry_id' => $e->ID, 'message' => $error->get_error_message() ) );
372 1
					return __( 'You are not allowed to view this content.', 'gravityview' );
373
				}
374
			}
375
376 2
			$renderer = new Entry_Renderer();
377 2
			return $renderer->render( $entry, $view, $request );
378
		}
379
380
		/**
381
		 * Plain old View.
382
		 */
383 5
		$renderer = new View_Renderer();
384 5
		return $renderer->render( $view, $request );
385
	}
386
387
	/**
388
	 * Checks whether this view can be accessed or not.
389
	 *
390
	 * @param string[]    $context The context we're asking for access from.
391
	 *                             Can any and as many of one of:
392
	 *                                 edit      An edit context.
393
	 *                                 single    A single context.
394
	 *                                 cpt       The custom post type single page acessed.
395
	 *                                 shortcode Embedded as a shortcode.
396
	 *                                 oembed    Embedded as an oEmbed.
397
	 *                                 rest      A REST call.
398
	 * @param \GV\Request $request The request
399
	 *
400
	 * @return bool|\WP_Error An error if this View shouldn't be rendered here.
401
	 */
402 29
	public function can_render( $context = null, $request = null ) {
403 29
		if ( ! $request ) {
404 7
			$request = gravityview()->request;
405
		}
406
407 29
		if ( ! is_array( $context ) ) {
408 6
			$context = array();
409
		}
410
411
		/**
412
		 * @filter `gravityview/view/can_render` Whether the view can be rendered or not.
413
		 * @param bool|\WP_Error $result  The result. Default: null.
414
		 * @param \GV\View       $view	The view.
415
		 * @param string[]       $context See \GV\View::can_render
416
		 * @param \GV\Request    $request The request.
417
		 */
418 29
		if ( ! is_null( $result = apply_filters( 'gravityview/view/can_render', null, $this, $context, $request ) ) ) {
419
			return $result;
420
		}
421
422 29
		if ( in_array( 'rest', $context ) ) {
423
			// REST
424 8
			if ( gravityview()->plugin->settings->get( 'rest_api' ) === '1' && $this->settings->get( 'rest_disable' ) === '1' ) {
425 1
				return new \WP_Error( 'gravityview/rest_disabled' );
426 8
			} elseif ( gravityview()->plugin->settings->get( 'rest_api' ) !== '1' && $this->settings->get( 'rest_enable' ) !== '1' ) {
427 1
				return new \WP_Error( 'gravityview/rest_disabled' );
428
			}
429
		}
430
431 29
		if ( in_array( 'csv', $context ) ) {
432 7
			if ( $this->settings->get( 'csv_enable' ) !== '1' ) {
433 1
				return new \WP_Error( 'gravityview/csv_disabled', 'The CSV endpoint is not enabled for this View' );
434
			}
435
		}
436
437
		/**
438
		 * This View is password protected. Nothing to do here.
439
		 */
440 29
		if ( post_password_required( $this->ID ) ) {
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
441 3
			gravityview()->log->notice( 'Post password is required for View #{view_id}', array( 'view_id' => $this->ID ) );
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
442 3
			return new \WP_Error( 'gravityview/post_password_required' );
443
		}
444
445 29
		if ( ! $this->form ) {
446
			gravityview()->log->notice( 'View #{id} has no form attached to it.', array( 'id' => $this->ID ) );
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
447
			return new \WP_Error( 'gravityview/no_form_attached' );
448
		}
449
450 29
		if ( ! in_array( 'shortcode', $context ) ) {
451
			/**
452
			 * Is this View directly accessible via a post URL?
453
			 *
454
			 * @see https://codex.wordpress.org/Function_Reference/register_post_type#public
455
			 */
456
457
			/**
458
			 * @filter `gravityview_direct_access` Should Views be directly accessible, or only visible using the shortcode?
459
			 * @deprecated
460
			 * @param[in,out] boolean `true`: allow Views to be accessible directly. `false`: Only allow Views to be embedded. Default: `true`
461
			 * @param int $view_id The ID of the View currently being requested. `0` for general setting
462
			 */
463 21
			$direct_access = apply_filters( 'gravityview_direct_access', true, $this->ID );
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
464
465
			/**
466
			 * @filter `gravityview/request/output/direct` Should this View be directly accessbile?
467
			 * @since 2.0
468
			 * @param[in,out] boolean Accessible or not. Default: accessbile.
469
			 * @param \GV\View $view The View we're trying to directly render here.
470
			 * @param \GV\Request $request The current request.
471
			 */
472 21
			if ( ! apply_filters( 'gravityview/view/output/direct', $direct_access, $this, $request ) ) {
473
				return new \WP_Error( 'gravityview/no_direct_access' );
474
			}
475
476
			/**
477
			 * Is this View an embed-only View? If so, don't allow rendering here,
478
			 *  as this is a direct request.
479
			 */
480 21
			if ( $this->settings->get( 'embed_only' ) && ! \GVCommon::has_cap( 'read_private_gravityviews' ) ) {
481 1
				return new \WP_Error( 'gravityview/embed_only' );
482
			}
483
		}
484
485
		/** Private, pending, draft, etc. */
486 29
		$public_states = get_post_stati( array( 'public' => true ) );
487 29
		if ( ! in_array( $this->post_status, $public_states ) && ! \GVCommon::has_cap( 'read_gravityview', $this->ID ) ) {
0 ignored issues
show
Documentation introduced by
The property post_status does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
488 3
			gravityview()->log->notice( 'The current user cannot access this View #{view_id}', array( 'view_id' => $this->ID ) );
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
489 3
			return new \WP_Error( 'gravityview/not_public' );
490
		}
491
492 29
		return true;
493
	}
494
495
	/**
496
	 * Get joins associated with a view
497
	 *
498
	 * @param \WP_Post $post GravityView CPT to get joins for
499
	 *
500
	 * @api
501
	 * @since 2.0.11
502
	 *
503
	 * @return \GV\Join[] Array of \GV\Join instances
504
	 */
505 171
	public static function get_joins( $post ) {
506 171
		$joins = array();
507
508 171
		if ( ! gravityview()->plugin->supports( Plugin::FEATURE_JOINS ) ) {
509
			gravityview()->log->error( 'Cannot get joined forms; joins feature not supported.' );
510
			return $joins;
511
		}
512
513 171
		if ( ! $post || 'gravityview' !== get_post_type( $post ) ) {
514
			gravityview()->log->error( 'Only "gravityview" post types can be \GV\View instances.' );
515
			return $joins;
516
		}
517
518 171
		$joins_meta = get_post_meta( $post->ID, '_gravityview_form_joins', true );
519
520 171
		if ( empty( $joins_meta ) ) {
521 160
			return $joins;
522
		}
523
524 11
		foreach ( $joins_meta as $meta ) {
525 11
			if ( ! is_array( $meta ) || count( $meta ) != 4 ) {
526
				continue;
527
			}
528
529 11
			list( $join, $join_column, $join_on, $join_on_column ) = $meta;
530
531 11
			$join    = GF_Form::by_id( $join );
532 11
			$join_on = GF_Form::by_id( $join_on );
533
534 11
			$join_column    = is_numeric( $join_column ) ? GF_Field::by_id( $join, $join_column ) : Internal_Field::by_id( $join_column );
535 11
			$join_on_column = is_numeric( $join_on_column ) ? GF_Field::by_id( $join_on, $join_on_column ) : Internal_Field::by_id( $join_on_column );
536
537 11
			$joins [] = new Join( $join, $join_column, $join_on, $join_on_column );
538
		}
539
540 11
		return $joins;
541
	}
542
543
	/**
544
	 * Get joined forms associated with a view
545
	 * In no particular order.
546
	 *
547
	 * @since 2.0.11
548
	 *
549
	 * @api
550
	 * @since 2.0
551
	 * @param int $post_id ID of the View
552
	 *
553
	 * @return \GV\GF_Form[] Array of \GV\GF_Form instances
554
	 */
555 2
	public static function get_joined_forms( $post_id ) {
556 2
		$forms = array();
557
558 2
		if ( ! gravityview()->plugin->supports( Plugin::FEATURE_JOINS ) ) {
559
			gravityview()->log->error( 'Cannot get joined forms; joins feature not supported.' );
560
			return $forms;
561
		}
562
563 2
		if ( ! $post_id || ! gravityview()->plugin->supports( Plugin::FEATURE_JOINS ) ) {
564
			return $forms;
565
		}
566
567 2
		if ( empty( $post_id ) ) {
568
			gravityview()->log->error( 'Cannot get joined forms; $post_id was empty' );
569
			return $forms;
570
		}
571
572 2
		$joins_meta = get_post_meta( $post_id, '_gravityview_form_joins', true );
573
574 2
		if ( empty( $joins_meta ) ) {
575
			return $forms;
576
		}
577
578 2
		foreach ( $joins_meta  as $meta ) {
579 2
			if ( ! is_array( $meta ) || count( $meta ) != 4 ) {
580
				continue;
581
			}
582
583 2
			list( $join, $join_column, $join_on, $join_on_column ) = $meta;
584
585 2
			if ( $form = GF_Form::by_id( $join_on ) ) {
586 2
				$forms[ $join_on ] = $form;
587
			}
588
589 2
			if ( $form = GF_Form::by_id( $join ) ) {
590 2
				$forms[ $join ] = $form;
591
			}
592
		}
593
594 2
		return $forms;
595
	}
596
597
	/**
598
	 * Get unions associated with a view
599
	 *
600
	 * @param \WP_Post $post GravityView CPT to get unions for
601
	 *
602
	 * @api
603
	 * @since 2.2.2
604
	 *
605
	 * @return \GV\Field[][] Array of unions (see self::$unions)
606
	 */
607 171
	public static function get_unions( $post ) {
608 171
		$unions = array();
609
610 171
		if ( ! gravityview()->plugin->supports( Plugin::FEATURE_UNIONS ) ) {
611
			gravityview()->log->error( 'Cannot get unions; unions feature not supported.' );
612
			return $unions;
613
		}
614
615 171
		if ( ! $post || 'gravityview' !== get_post_type( $post ) ) {
616
			gravityview()->log->error( 'Only "gravityview" post types can be \GV\View instances.' );
617
			return $unions;
618
		}
619
620 171
		$fields = get_post_meta( $post->ID, '_gravityview_directory_fields', true );
621
622 171
		if ( empty( $fields ) ) {
623 1
			return $unions;
624
		}
625
626 170
		foreach ( $fields as $location => $_fields ) {
627 170
			if ( strpos( $location, 'directory_' ) !== 0 ) {
628 49
				continue;
629
			}
630
631 122
			foreach ( $_fields as $field ) {
632 122
				if ( ! empty( $field['unions'] ) ) {
633 1
					foreach ( $field['unions'] as $form_id => $field_id ) {
634 1
						if ( ! isset( $unions[ $form_id ] ) ) {
635 1
							$unions[ $form_id ] = array();
636
						}
637
638 1
						$unions[ $form_id ][ $field['id'] ] =
639 1
							is_numeric( $field_id ) ? \GV\GF_Field::by_id( \GV\GF_Form::by_id( $form_id ), $field_id ) : \GV\Internal_Field::by_id( $field_id );
640
					}
641
				}
642
			}
643
644 122
			break;
645
		}
646
647
		// @todo We'll probably need to backfill null unions
648
649 170
		return $unions;
650
	}
651
652
	/**
653
	 * Construct a \GV\View instance from a \WP_Post.
654
	 *
655
	 * @param \WP_Post $post The \WP_Post instance to wrap.
656
	 *
657
	 * @api
658
	 * @since 2.0
659
	 * @return \GV\View|null An instance around this \WP_Post if valid, null otherwise.
660
	 */
661 172
	public static function from_post( $post ) {
662
663 172
		if ( ! $post || 'gravityview' !== get_post_type( $post ) ) {
664 2
			gravityview()->log->error( 'Only gravityview post types can be \GV\View instances.' );
665 2
			return null;
666
		}
667
668 172
		if ( $view = Utils::get( self::$cache, "View::from_post:{$post->ID}" ) ) {
669
			/**
670
			 * @filter `gravityview/view/get` Override View.
671
			 * @param \GV\View $view The View instance pointer.
672
			 * @since 2.1
673
			 */
674 97
			do_action_ref_array( 'gravityview/view/get', array( &$view ) );
675
676 97
			return $view;
677
		}
678
679 172
		$view = new self();
680 172
		$view->post = $post;
681
682
		/** Get connected form. */
683 172
		$view->form = GF_Form::by_id( $view->_gravityview_form_id );
0 ignored issues
show
Documentation introduced by
The property _gravityview_form_id does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
684 172
		if ( ! $view->form ) {
685
			gravityview()->log->error( 'View #{view_id} tried attaching non-existent Form #{form_id} to it.', array(
686
				'view_id' => $view->ID,
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
687
				'form_id' => $view->_gravityview_form_id ? : 0,
0 ignored issues
show
Documentation introduced by
The property _gravityview_form_id does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
688
			) );
689
		}
690
691 172
		$view->joins = $view::get_joins( $post );
692
693 172
		$view->unions = $view::get_unions( $post );
694
695
		/**
696
		 * @filter `gravityview/configuration/fields` Filter the View fields' configuration array.
697
		 * @since 1.6.5
698
		 *
699
		 * @deprecated Use `gravityview/view/configuration/fields` or `gravityview/view/fields` filters.
700
		 *
701
		 * @param $fields array Multi-array of fields with first level being the field zones.
702
		 * @param $view_id int The View the fields are being pulled for.
703
		 */
704 172
		$configuration = apply_filters( 'gravityview/configuration/fields', (array)$view->_gravityview_directory_fields, $view->ID );
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
705
706
		/**
707
		 * @filter `gravityview/view/configuration/fields` Filter the View fields' configuration array.
708
		 * @since 2.0
709
		 *
710
		 * @param array $fields Multi-array of fields with first level being the field zones.
711
		 * @param \GV\View $view The View the fields are being pulled for.
712
		 */
713 172
		$configuration = apply_filters( 'gravityview/view/configuration/fields', $configuration, $view );
714
715
		/**
716
		 * @filter `gravityview/view/fields` Filter the Field Collection for this View.
717
		 * @since 2.0
718
		 *
719
		 * @param \GV\Field_Collection $fields A collection of fields.
720
		 * @param \GV\View $view The View the fields are being pulled for.
721
		 */
722 172
		$view->fields = apply_filters( 'gravityview/view/fields', Field_Collection::from_configuration( $configuration ), $view );
723
724
		/**
725
		 * @filter `gravityview/view/configuration/widgets` Filter the View widgets' configuration array.
726
		 * @since 2.0
727
		 *
728
		 * @param array $fields Multi-array of widgets with first level being the field zones.
729
		 * @param \GV\View $view The View the widgets are being pulled for.
730
		 */
731 172
		$configuration = apply_filters( 'gravityview/view/configuration/widgets', (array)$view->_gravityview_directory_widgets, $view );
732
733
		/**
734
		 * @filter `gravityview/view/widgets` Filter the Widget Collection for this View.
735
		 * @since 2.0
736
		 *
737
		 * @param \GV\Widget_Collection $widgets A collection of widgets.
738
		 * @param \GV\View $view The View the widgets are being pulled for.
739
		 */
740 172
		$view->widgets = apply_filters( 'gravityview/view/widgets', Widget_Collection::from_configuration( $configuration ), $view );
741
742
		/** View configuration. */
743 172
		$view->settings->update( gravityview_get_template_settings( $view->ID ) );
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
744
745
		/** Add the template name into the settings. */
746 172
		$view->settings->update( array( 'template' => gravityview_get_template_id( $view->ID ) ) );
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
747
748
		/** View basics. */
749 172
		$view->settings->update( array(
750 172
			'id' => $view->ID,
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
751
		) );
752
753 172
		self::$cache[ "View::from_post:{$post->ID}" ] = &$view;
754
755
		/**
756
		 * @filter `gravityview/view/get` Override View.
757
		 * @param \GV\View $view The View instance pointer.
758
		 * @since 2.1
759
		 */
760 172
		do_action_ref_array( 'gravityview/view/get', array( &$view ) );
761
762 172
		return $view;
763
	}
764
765
	/**
766
	 * Flush the view cache.
767
	 *
768
	 * @param int $view_id The View to reset cache for. Optional. Default: resets everything.
769
	 *
770
	 * @internal
771
	 */
772 186
	public static function _flush_cache( $view_id = null ) {
773 186
		if ( $view_id ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $view_id of type integer|null 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...
774 180
			unset( self::$cache[ "View::from_post:$view_id" ] );
775 180
			return;
776
		}
777 95
		self::$cache = array();
778 95
	}
779
780
	/**
781
	 * Construct a \GV\View instance from a post ID.
782
	 *
783
	 * @param int|string $post_id The post ID.
784
	 *
785
	 * @api
786
	 * @since 2.0
787
	 * @return \GV\View|null An instance around this \WP_Post or null if not found.
788
	 */
789 110
	public static function by_id( $post_id ) {
790 110
		if ( ! $post_id || ! $post = get_post( $post_id ) ) {
791 3
			return null;
792
		}
793 110
		return self::from_post( $post );
794
	}
795
796
	/**
797
	 * Determines if a view exists to begin with.
798
	 *
799
	 * @param int|\WP_Post|null $view The WordPress post ID, a \WP_Post object or null for global $post;
800
	 *
801
	 * @api
802
	 * @since 2.0
803
	 * @return bool Whether the post exists or not.
804
	 */
805 23
	public static function exists( $view ) {
806 23
		return get_post_type( $view ) == 'gravityview';
807
	}
808
809
	/**
810
	 * ArrayAccess compatibility layer with GravityView_View_Data::$views
811
	 *
812
	 * @internal
813
	 * @deprecated
814
	 * @since 2.0
815
	 * @return bool Whether the offset exists or not, limited to GravityView_View_Data::$views element keys.
816
	 */
817 15
	public function offsetExists( $offset ) {
818 15
		$data_keys = array( 'id', 'view_id', 'form_id', 'template_id', 'atts', 'fields', 'widgets', 'form' );
819 15
		return in_array( $offset, $data_keys );
820
	}
821
822
	/**
823
	 * ArrayAccess compatibility layer with GravityView_View_Data::$views
824
	 *
825
	 * Maps the old keys to the new data;
826
	 *
827
	 * @internal
828
	 * @deprecated
829
	 * @since 2.0
830
	 *
831
	 * @return mixed The value of the requested view data key limited to GravityView_View_Data::$views element keys. If offset not found, return null.
832
	 */
833 15
	public function offsetGet( $offset ) {
834
835 15
		gravityview()->log->notice( 'This is a \GV\View object should not be accessed as an array.' );
836
837 15
		if ( ! isset( $this[ $offset ] ) ) {
838
			return null;
839
		}
840
841 15
		switch ( $offset ) {
842 15
			case 'id':
843 15
			case 'view_id':
844 1
				return $this->ID;
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
845 15
			case 'form':
846 15
				return $this->form;
847 1
			case 'form_id':
848 1
				return $this->form ? $this->form->ID : null;
849 1
			case 'atts':
850
				return $this->settings->as_atts();
0 ignored issues
show
Deprecated Code introduced by
The method GV\View_Settings::as_atts() has been deprecated.

This method has been deprecated.

Loading history...
851 1
			case 'template_id':
852 1
				return $this->settings->get( 'template' );
853
			case 'widgets':
854
				return $this->widgets->as_configuration();
855
		}
856
857
		return null;
858
	}
859
860
	/**
861
	 * ArrayAccess compatibility layer with GravityView_View_Data::$views
862
	 *
863
	 * @internal
864
	 * @deprecated
865
	 * @since 2.0
866
	 *
867
	 * @return void
868
	 */
869 1
	public function offsetSet( $offset, $value ) {
870 1
		gravityview()->log->error( 'The old view data is no longer mutable. This is a \GV\View object should not be accessed as an array.' );
871 1
	}
872
873
	/**
874
	 * ArrayAccess compatibility layer with GravityView_View_Data::$views
875
	 *
876
	 * @internal
877
	 * @deprecated
878
	 * @since 2.0
879
	 * @return void
880
	 */
881 1
	public function offsetUnset( $offset ) {
882 1
		gravityview()->log->error( 'The old view data is no longer mutable. This is a \GV\View object should not be accessed as an array.' );
883 1
	}
884
885
	/**
886
	 * Be compatible with the old data object.
887
	 *
888
	 * Some external code expects an array (doing things like foreach on this, or array_keys)
889
	 *  so let's return an array in the old format for such cases. Do not use unless using
890
	 *  for back-compatibility.
891
	 *
892
	 * @internal
893
	 * @deprecated
894
	 * @since 2.0
895
	 * @return array
896
	 */
897 26
	public function as_data() {
898
		return array(
899 26
			'id' => $this->ID,
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
900 26
			'view_id' => $this->ID,
0 ignored issues
show
Documentation introduced by
The property ID does not exist on object<GV\View>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
901 26
			'form_id' => $this->form ? $this->form->ID : null,
902 26
			'form' => $this->form ? gravityview_get_form( $this->form->ID ) : null,
903 26
			'atts' => $this->settings->as_atts(),
0 ignored issues
show
Deprecated Code introduced by
The method GV\View_Settings::as_atts() has been deprecated.

This method has been deprecated.

Loading history...
904 26
			'fields' => $this->fields->by_visible()->as_configuration(),
905 26
			'template_id' => $this->settings->get( 'template' ),
906 26
			'widgets' => $this->widgets->as_configuration(),
907
		);
908
	}
909
910
	/**
911
	 * Retrieve the entries for the current view and request.
912
	 *
913
	 * @param \GV\Request The request. Unused for now.
914
	 *
915
	 * @return \GV\Entry_Collection The entries.
916
	 */
917 65
	public function get_entries( $request = null ) {
918 65
		$entries = new \GV\Entry_Collection();
919 65
		if ( $this->form ) {
920 65
			$parameters = $this->settings->as_atts();
0 ignored issues
show
Deprecated Code introduced by
The method GV\View_Settings::as_atts() has been deprecated.

This method has been deprecated.

Loading history...
921
922
			/**
923
			 * Remove multiple sorting before calling legacy filters.
924
			 * This allows us to fake it till we make it.
925
			 */
926 65
			if ( ! empty( $parameters['sort_field'] ) && is_array( $parameters['sort_field'] ) ) {
927 2
				$has_multisort = true;
928 2
				$parameters['sort_field'] = reset( $parameters['sort_field'] );
929 2
				if ( ! empty( $parameters['sort_direction'] ) && is_array( $parameters['sort_direction'] ) ) {
930 2
					$parameters['sort_direction'] = reset( $parameters['sort_direction'] );
931
				}
932
			}
933
934
			/**
935
			 * @todo: Stop using _frontend and use something like $request->get_search_criteria() instead
936
			 */
937 65
			$parameters = \GravityView_frontend::get_view_entries_parameters( $parameters, $this->form->ID );
938 65
			$parameters['context_view_id'] = $this->ID;
0 ignored issues
show
Bug introduced by
The property ID does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
939 65
			$parameters = \GVCommon::calculate_get_entries_criteria( $parameters, $this->form->ID );
940
941 65
			if ( $request instanceof REST\Request ) {
942 6
				$atts = $this->settings->as_atts();
0 ignored issues
show
Deprecated Code introduced by
The method GV\View_Settings::as_atts() has been deprecated.

This method has been deprecated.

Loading history...
943 6
				$paging_parameters = wp_parse_args( $request->get_paging(), array(
944 6
						'paging' => array( 'page_size' => $atts['page_size'] ),
945
					) );
946 6
				$parameters['paging'] = $paging_parameters['paging'];
947
			}
948
949 65
			$page = Utils::get( $parameters['paging'], 'current_page' ) ?
950 65
				: ( ( ( $parameters['paging']['offset'] - $this->settings->get( 'offset' ) ) / $parameters['paging']['page_size'] ) + 1 );
951
952
			/**
953
			 * Cleanup duplicate field_filter parameters to simplify the query.
954
			 */
955 65
			$unique_field_filters = array();
956 65
			foreach ( $parameters['search_criteria']['field_filters'] as $key => $filter ) {
957 11
				if ( 'mode' === $key ) {
958 10
					$unique_field_filters['mode'] = $filter;
959 11
				} else if ( ! in_array( $filter, $unique_field_filters ) ) {
960 11
					$unique_field_filters[] = $filter;
961
				}
962
			}
963 65
			$parameters['search_criteria']['field_filters'] = $unique_field_filters;
964
965 65
			if ( ! empty( $parameters['search_criteria']['field_filters'] ) ) {
966 11
				gravityview()->log->notice( 'search_criteria/field_filters is not empty, third-party code may be using legacy search_criteria filters.' );
967
			}
968
969 65
			if ( gravityview()->plugin->supports( Plugin::FEATURE_GFQUERY ) ) {
970
971 65
				$query_class = $this->get_query_class();
972
973
				/** @var \GF_Query $query */
974 65
				$query = new $query_class( $this->form->ID, $parameters['search_criteria'], $parameters['sorting'] );
975
976
				/**
977
				 * Apply multisort.
978
				 */
979 65
				if ( ! empty( $has_multisort ) ) {
980 2
					$atts = $this->settings->as_atts();
0 ignored issues
show
Deprecated Code introduced by
The method GV\View_Settings::as_atts() has been deprecated.

This method has been deprecated.

Loading history...
981
982 2
					$view_setting_sort_field_ids = \GV\Utils::get( $atts, 'sort_field', array() );
983 2
					$view_setting_sort_directions = \GV\Utils::get( $atts, 'sort_direction', array() );
984
985 2
					$has_sort_query_param = ! empty( $_GET['sort'] ) && is_array( $_GET['sort'] );
986
987 2
					if( $has_sort_query_param ) {
988
						$has_sort_query_param = array_filter( array_values( $_GET['sort'] ) );
989
					}
990
991 2
					if ( $this->settings->get( 'sort_columns' ) && $has_sort_query_param ) {
992
						$sort_field_ids = array_keys( $_GET['sort'] );
993
						$sort_directions = array_values( $_GET['sort'] );
994
					} else {
995 2
						$sort_field_ids = $view_setting_sort_field_ids;
996 2
						$sort_directions = $view_setting_sort_directions;
997
					}
998
999 2
					$skip_first = false;
1000
1001 2
					foreach ( (array) $sort_field_ids as $key => $sort_field_id ) {
1002
1003 2
						if ( ! $skip_first && ! $has_sort_query_param ) {
1004 2
							$skip_first = true; // Skip the first one, it's already in the query
1005 2
							continue;
1006
						}
1007
1008 1
						$sort_field_id = \GravityView_frontend::_override_sorting_id_by_field_type( $sort_field_id, $this->form->ID );
1009 1
						$sort_direction = strtoupper( \GV\Utils::get( $sort_directions, $key, 'ASC' ) );
1010
1011 1
						if ( ! empty( $sort_field_id ) ) {
1012 1
							$order = new \GF_Query_Column( $sort_field_id, $this->form->ID );
1013 1
							if ( \GVCommon::is_field_numeric( $this->form->ID, $sort_field_id ) ) {
1014
								$order = \GF_Query_Call::CAST( $order, defined( 'GF_Query::TYPE_DECIMAL' ) ? \GF_Query::TYPE_DECIMAL : \GF_Query::TYPE_SIGNED );
1015
							}
1016
1017 1
							$query->order( $order, $sort_direction );
1018
						}
1019
					}
1020
				}
1021
1022
				/**
1023
				 * Merge time subfield sorts.
1024
				 */
1025 65
				add_filter( 'gform_gf_query_sql', $gf_query_timesort_sql_callback = function( $sql ) use ( &$query ) {
1026 65
					$q = $query->_introspect();
1027 65
					$orders = array();
1028
1029 65
					$merged_time = false;
1030
1031 65
					foreach ( $q['order'] as $oid => $order ) {
1032 65
						if ( $order[0] instanceof \GF_Query_Column ) {
0 ignored issues
show
Bug introduced by
The class GF_Query_Column does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
1033 64
							$column = $order[0];
1034 1
						} else if ( $order[0] instanceof \GF_Query_Call ) {
0 ignored issues
show
Bug introduced by
The class GF_Query_Call does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
1035 1
							if ( count( $order[0]->columns ) != 1 || ! $order[0]->columns[0] instanceof \GF_Query_Column ) {
0 ignored issues
show
Bug introduced by
The class GF_Query_Column does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
1036
								$orders[ $oid ] = $order;
1037
								continue; // Need something that resembles a single sort
1038
							}
1039 1
							$column = $order[0]->columns[0];
1040
						}
1041
1042 65
						if ( ( ! $field = \GFAPI::get_field( $column->source, $column->field_id ) ) || $field->type !== 'time' ) {
0 ignored issues
show
Bug introduced by
The variable $column does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1043 64
							$orders[ $oid ] = $order;
1044 64
							continue; // Not a time field
1045
						}
1046
1047 1
						if ( ! class_exists( '\GV\Mocks\GF_Query_Call_TIMESORT' ) ) {
1048 1
							require_once gravityview()->plugin->dir( 'future/_mocks.timesort.php' );
1049
						}
1050
1051 1
						$orders[ $oid ] = array(
1052 1
							new \GV\Mocks\GF_Query_Call_TIMESORT( 'timesort', array( $column, $sql ) ),
1053 1
							$order[1] // Mock it!
1054
						);
1055
1056 1
						$merged_time = true;
1057
					}
1058
1059 65
					if ( $merged_time ) {
1060
						/**
1061
						 * ORDER again.
1062
						 */
1063 1
						if ( ! empty( $orders ) && $_orders = $query->_order_generate( $orders ) ) {
1064 1
							$sql['order'] = 'ORDER BY ' . implode( ', ', $_orders );
1065
						}
1066
					}
1067
1068 65
					return $sql;
1069 65
				} );
1070
1071 65
				$query->limit( $parameters['paging']['page_size'] )
1072 65
					->offset( ( ( $page - 1 ) * $parameters['paging']['page_size'] ) + $this->settings->get( 'offset' ) );
1073
1074
				/**
1075
				 * Any joins?
1076
				 */
1077 65
				if ( gravityview()->plugin->supports( Plugin::FEATURE_JOINS ) && count( $this->joins ) ) {
1078
1079 11
					$is_admin_and_can_view = $this->settings->get( 'admin_show_all_statuses' ) && \GVCommon::has_cap( 'gravityview_moderate_entries', $this->ID );
1080
1081 11
					foreach ( $this->joins as $join ) {
1082 11
						$query = $join->as_query_join( $query );
1083
1084 11
						if ( $this->settings->get( 'multiple_forms_disable_null_joins' ) ) {
1085
1086
							// Disable NULL outputs
1087
							$condition = new \GF_Query_Condition(
1088
								new \GF_Query_Column( $join->join_on_column->ID, $join->join_on->ID ),
0 ignored issues
show
Bug introduced by
The property ID does not seem to exist in GV\Source.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
1089
								\GF_Query_Condition::NEQ,
1090
								new \GF_Query_Literal( '' )
1091
							);
1092
1093
							$query_parameters = $query->_introspect();
1094
1095
							$query->where( \GF_Query_Condition::_and( $query_parameters['where'], $condition ) );
1096
						}
1097
1098
						/**
1099
						 * This is a temporary stub filter, until GF_Query supports NULL conditions.
1100
						 * Do not use! This filter will be removed.
1101
						 */
1102 11
						if ( defined( 'GF_Query_Condition::NULL' ) ) {
1103 11
							$is_null_condition_native = true;
1104
						} else {
1105
							$is_null_condition_class = apply_filters( 'gravityview/query/is_null_condition', null );
1106
							$is_null_condition_native = false;
1107
						}
1108
1109
						// Filter to active entries only
1110 11
						$condition = new \GF_Query_Condition(
1111 11
							new \GF_Query_Column( 'status', $join->join_on->ID ),
1112 11
							\GF_Query_Condition::EQ,
1113 11
							new \GF_Query_Literal( 'active' )
1114
						);
1115
1116 11
						if ( $is_null_condition_native ) {
1117 11
							$condition = \GF_Query_Condition::_or( $condition, new \GF_Query_Condition(
1118 11
								new \GF_Query_Column( 'status', $join->join_on->ID ),
1119 11
								\GF_Query_Condition::IS,
1120 11
								\GF_Query_Condition::NULL
1121
							) );
1122
						} else if ( ! is_null( $is_null_condition_class ) ) {
1123
							$condition = \GF_Query_Condition::_or( $condition, new $is_null_condition_class(
0 ignored issues
show
Bug introduced by
The variable $is_null_condition_class does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
1124
								new \GF_Query_Column( 'status', $join->join_on->ID )
1125
							) );
1126
						}
1127
1128 11
						$q = $query->_introspect();
1129 11
						$query->where( \GF_Query_Condition::_and( $q['where'], $condition ) );
1130
1131 11
						if ( $this->settings->get( 'show_only_approved' ) && ! $is_admin_and_can_view ) {
1132
1133
							// Show only approved joined entries
1134 1
							$condition = new \GF_Query_Condition(
1135 1
								new \GF_Query_Column( \GravityView_Entry_Approval::meta_key, $join->join_on->ID ),
1136 1
								\GF_Query_Condition::EQ,
1137 1
								new \GF_Query_Literal( \GravityView_Entry_Approval_Status::APPROVED )
1138
							);
1139
1140 1
							if ( $is_null_condition_native ) {
1141 1
								$condition = \GF_Query_Condition::_or( $condition, new \GF_Query_Condition(
1142 1
									new \GF_Query_Column( \GravityView_Entry_Approval::meta_key, $join->join_on->ID ),
1143 1
									\GF_Query_Condition::IS,
1144 1
									\GF_Query_Condition::NULL
1145
								) );
1146
							} else if ( ! is_null( $is_null_condition_class ) ) {
1147
								$condition = \GF_Query_Condition::_or( $condition, new $is_null_condition_class(
1148
									new \GF_Query_Column( \GravityView_Entry_Approval::meta_key, $join->join_on->ID )
1149
								) );
1150
							}
1151
1152 1
							$query_parameters = $query->_introspect();
1153
1154 1
							$query->where( \GF_Query_Condition::_and( $query_parameters['where'], $condition ) );
1155
						}
1156
					}
1157
				
1158
				/**
1159
				 * Unions?
1160
				 */
1161 54
				} else if ( gravityview()->plugin->supports( Plugin::FEATURE_UNIONS ) && count( $this->unions ) ) {
1162 1
					$query_parameters = $query->_introspect();
1163
1164 1
					$unions_sql = array();
1165
1166
					/**
1167
					 * @param \GF_Query_Condition $condition
1168
					 * @param array $fields
1169
					 * @param $recurse
1170
					 *
1171
					 * @return \GF_Query_Condition
1172
					 */
1173 1
					$where_union_substitute = function( $condition, $fields, $recurse ) {
1174 1
						if ( $condition->expressions ) {
1175 1
							$conditions = array();
1176
1177 1
							foreach ( $condition->expressions as $_condition ) {
1178 1
								$conditions[] = $recurse( $_condition, $fields, $recurse );
1179
							}
1180
1181 1
							return call_user_func_array(
1182 1
								array( '\GF_Query_Condition', $condition->operator == 'AND' ? '_and' : '_or' ),
1183 1
								$conditions
1184
							);
1185
						}
1186
1187 1
						if ( ! ( $condition->left && $condition->left instanceof \GF_Query_Column ) || ( ! $condition->left->is_entry_column() && ! $condition->left->is_meta_column() ) ) {
0 ignored issues
show
Bug introduced by
The class GF_Query_Column does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
1188 1
							return new \GF_Query_Condition(
1189 1
								new \GF_Query_Column( $fields[ $condition->left->field_id ]->ID ),
1190 1
								$condition->operator,
1191 1
								$condition->right
1192
							);
1193
						}
1194
1195 1
						return $condition;
1196 1
					};
1197
1198 1
					foreach ( $this->unions as $form_id => $fields ) {
1199
1200
						// Build a new query for every unioned form
1201 1
						$query_class = $this->get_query_class();
1202
1203
						/** @var \GF_Query|\GF_Patched_Query $q */
1204 1
						$q = new $query_class( $form_id );
1205
1206
						// Copy the WHERE clauses but substitute the field_ids to the respective ones
1207 1
						$q->where( $where_union_substitute( $query_parameters['where'], $fields, $where_union_substitute ) );
1208
1209
						// Copy the ORDER clause and substitute the field_ids to the respective ones
1210 1
						foreach ( $query_parameters['order'] as $order ) {
1211 1
							list( $column, $_order ) = $order;
1212
1213 1
							if ( $column && $column instanceof \GF_Query_Column ) {
0 ignored issues
show
Bug introduced by
The class GF_Query_Column does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
1214 1
								if ( ! $column->is_entry_column() && ! $column->is_meta_column() ) {
1215 1
									$column = new \GF_Query_Column( $fields[ $column->field_id ]->ID );
1216
								}
1217
1218 1
								$q->order( $column, $_order );
1219
							}
1220
						}
1221
1222 1
						add_filter( 'gform_gf_query_sql', $gf_query_sql_callback = function( $sql ) use ( &$unions_sql ) {
1223
							// Remove SQL_CALC_FOUND_ROWS as it's not needed in UNION clauses
1224 1
							$select = 'UNION ALL ' . str_replace( 'SQL_CALC_FOUND_ROWS ', '', $sql['select'] );
1225
1226
							// Record the SQL
1227 1
							$unions_sql[] = array(
1228
								// Remove columns, we'll rebuild them
1229 1
								'select'  => preg_replace( '#DISTINCT (.*)#', 'DISTINCT ', $select ),
1230 1
								'from'    => $sql['from'],
1231 1
								'join'    => $sql['join'],
1232 1
								'where'   => $sql['where'],
1233
								// Remove order and limit
1234
							);
1235
1236
							// Return empty query, no need to call the database
1237 1
							return array();
1238 1
						} );
1239
1240 1
						do_action_ref_array( 'gravityview/view/query', array( &$q, $this, $request ) );
1241
1242 1
						$q->get(); // Launch
1243
1244 1
						remove_filter( 'gform_gf_query_sql', $gf_query_sql_callback );
1245
					}
1246
1247 1
					add_filter( 'gform_gf_query_sql', $gf_query_sql_callback = function( $sql ) use ( $unions_sql ) {
1248
						// Remove SQL_CALC_FOUND_ROWS as it's not needed in UNION clauses
1249 1
						$sql['select'] = str_replace( 'SQL_CALC_FOUND_ROWS ', '', $sql['select'] );
1250
1251
						// Remove columns, we'll rebuild them
1252 1
						preg_match( '#DISTINCT (`[motc]\d+`.`.*?`)#', $sql['select'], $select_match );
1253 1
						$sql['select'] = preg_replace( '#DISTINCT (.*)#', 'DISTINCT ', $sql['select'] );
1254
1255 1
						$unions = array();
1256
1257
						// Transform selected columns to shared alias names
1258 1
						$column_to_alias = function( $column ) {
1259 1
							$column = str_replace( '`', '', $column );
1260 1
							return '`' . str_replace( '.', '_', $column ) . '`';
1261 1
						};
1262
1263
						// Add all the order columns into the selects, so we can order by the whole union group
1264 1
						preg_match_all( '#(`[motc]\d+`.`.*?`)#', $sql['order'], $order_matches );
1265
						
1266
						$columns = array(
1267 1
							sprintf( '%s AS %s', $select_match[1], $column_to_alias( $select_match[1] ) )
1268
						);
1269
1270 1
						foreach ( array_slice( $order_matches, 1 ) as $match ) {
1271 1
							$columns[] = sprintf( '%s AS %s', $match[0], $column_to_alias( $match[0] ) );
1272
1273
							// Rewrite the order columns to the shared aliases
1274 1
							$sql['order'] = str_replace( $match[0], $column_to_alias( $match[0] ), $sql['order'] );
1275
						}
1276
1277 1
						$columns = array_unique( $columns );
1278
1279
						// Add the columns to every UNION
1280 1
						foreach ( $unions_sql as $union_sql ) {
1281 1
							$union_sql['select'] .= implode( ', ', $columns );
1282 1
							$unions []= implode( ' ', $union_sql );
1283
						}
1284
1285
						// Add the columns to the main SELECT, but only grab the entry id column
1286 1
						$sql['select'] = 'SELECT SQL_CALC_FOUND_ROWS t1_id FROM (' . $sql['select'] . implode( ', ', $columns );
1287 1
						$sql['order'] = implode( ' ', $unions ) . ') AS u ' . $sql['order'];
1288
1289 1
						return $sql;
1290 1
					} );
1291
				}
1292
1293
				/**
1294
				 * @action `gravityview/view/query` Override the \GF_Query before the get() call.
1295
				 * @param \GF_Query $query The current query object reference
1296
				 * @param \GV\View $this The current view object
1297
				 * @param \GV\Request $request The request object
1298
				 */
1299 65
				do_action_ref_array( 'gravityview/view/query', array( &$query, $this, $request ) );
1300
1301 65
				gravityview()->log->debug( 'GF_Query parameters: ', array( 'data' => Utils::gf_query_debug( $query ) ) );
1302
1303
				/**
1304
				 * Map from Gravity Forms entries arrays to an Entry_Collection.
1305
				 */
1306 65
				if ( count( $this->joins ) ) {
1307 11
					foreach ( $query->get() as $entry ) {
1308 11
						$entries->add(
1309 11
							Multi_Entry::from_entries( array_map( '\GV\GF_Entry::from_entry', $entry ) )
1310
						);
1311
					}
1312
				} else {
1313 54
					array_map( array( $entries, 'add' ), array_map( '\GV\GF_Entry::from_entry', $query->get() ) );
1314
				}
1315
1316 65
				if ( isset( $gf_query_sql_callback ) ) {
1317 1
					remove_action( 'gform_gf_query_sql', $gf_query_sql_callback );
1318
				}
1319
1320 65
				if ( isset( $gf_query_timesort_sql_callback ) ) {
1321 65
					remove_action( 'gform_gf_query_sql', $gf_query_timesort_sql_callback );
1322
				}
1323
1324
				/**
1325
				 * Add total count callback.
1326
				 */
1327 65
				$entries->add_count_callback( function() use ( $query ) {
1328 31
					return $query->total_found;
1329 65
				} );
1330
			} else {
1331
				$entries = $this->form->entries
0 ignored issues
show
Documentation introduced by
The property entries does not exist on object<GV\Form>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
1332
					->filter( \GV\GF_Entry_Filter::from_search_criteria( $parameters['search_criteria'] ) )
1333
					->offset( $this->settings->get( 'offset' ) )
1334
					->limit( $parameters['paging']['page_size'] )
1335
					->page( $page );
1336
1337
				if ( ! empty( $parameters['sorting'] ) && is_array( $parameters['sorting'] && ! isset( $parameters['sorting']['key'] ) ) ) {
1338
					// Pluck off multisort arrays
1339
					$parameters['sorting'] = $parameters['sorting'][0];
1340
				}
1341
1342
				if ( ! empty( $parameters['sorting'] ) && ! empty( $parameters['sorting']['key'] ) ) {
1343
					$field = new \GV\Field();
1344
					$field->ID = $parameters['sorting']['key'];
1345
					$direction = strtolower( $parameters['sorting']['direction'] ) == 'asc' ? \GV\Entry_Sort::ASC : \GV\Entry_Sort::DESC;
1346
					$entries = $entries->sort( new \GV\Entry_Sort( $field, $direction ) );
1347
				}
1348
			}
1349
		}
1350
1351
		/**
1352
		 * @filter `gravityview/view/entries` Modify the entry fetching filters, sorts, offsets, limits.
1353
		 * @param \GV\Entry_Collection $entries The entries for this view.
1354
		 * @param \GV\View $view The view.
1355
		 * @param \GV\Request $request The request.
1356
		 */
1357 65
		return apply_filters( 'gravityview/view/entries', $entries, $this, $request );
1358
	}
1359
1360
	/**
1361
	 * Last chance to configure the output.
1362
	 *
1363
	 * Used for CSV output, for example.
1364
	 *
1365
	 * @return void
1366
	 */
1367 7
	public static function template_redirect() {
1368
		/**
1369
		 * CSV output.
1370
		 */
1371 7
		if ( ! get_query_var( 'csv' ) ) {
1372 1
			return;
1373
		}
1374
1375 7
		if ( ! $view = gravityview()->request->is_view() ) {
1376 1
			return;
1377
		}
1378
1379 7
		if ( is_wp_error( $error = $view->can_render( array( 'csv' ) ) ) ) {
1380 1
			gravityview()->log->error( 'Not rendering CSV: ' . $error->get_error_message() );
1381 1
			return;
1382
		}
1383
1384
		/**
1385
		 * Modify the name of the generated CSV file. Name will be sanitized using sanitize_file_name() before output.
1386
		 * @see sanitize_file_name()
1387
		 * @since 2.1
1388
		 * @param string   $filename File name used when downloading a CSV. Default is "{View title}.csv"
1389
		 * @param \GV\View $view Current View being rendered
1390
		 */
1391 7
		$filename = apply_filters( 'gravityview/output/csv/filename', get_the_title( $view->post ), $view );
1392
1393 7
		if ( ! defined( 'DOING_GRAVITYVIEW_TESTS' ) ) {
1394
			header( sprintf( 'Content-Disposition: attachment;filename="%s.csv"', sanitize_file_name( $filename ) ) );
1395
			header( 'Content-Transfer-Encoding: binary' );
1396
			header( 'Content-Type: text/csv' );
1397
		}
1398
1399 7
		ob_start();
1400 7
		$csv = fopen( 'php://output', 'w' );
1401
1402
		/**
1403
		 * Add da' BOM if GF uses it
1404
		 * @see GFExport::start_export()
1405
		 */
1406 7
		if ( apply_filters( 'gform_include_bom_export_entries', true, $view->form ? $view->form->form : null ) ) {
1407
			fputs( $csv, "\xef\xbb\xbf" );
1408
		}
1409
1410 7
		if ( $view->settings->get( 'csv_nolimit' ) ) {
1411 1
			$view->settings->update( array( 'page_size' => -1 ) );
1412
		}
1413
1414 7
		$entries = $view->get_entries();
1415
1416 7
		$headers_done = false;
1417 7
		$allowed = $headers = array();
1418
1419 7
		foreach ( $view->fields->by_position( "directory_*" )->by_visible()->all() as $id => $field ) {
1420 7
			$allowed[] = $field;
1421
		}
1422
1423 7
		$renderer = new Field_Renderer();
1424
1425 7
		foreach ( $entries->all() as $entry ) {
1426
1427 7
			$return = array();
1428
1429
			/**
1430
			 * @filter `gravityview/csv/entry/fields` Whitelist more entry fields by ID that are output in CSV requests.
1431
			 * @param[in,out] array $allowed The allowed ones, default by_visible, by_position( "context_*" ), i.e. as set in the View.
1432
			 * @param \GV\View $view The view.
1433
			 * @param \GV\Entry $entry WordPress representation of the item.
1434
			 */
1435 7
			$allowed_field_ids = apply_filters( 'gravityview/csv/entry/fields', wp_list_pluck( $allowed, 'ID' ), $view, $entry );
1436
1437 7
			$allowed = array_filter( $allowed, function( $field ) use ( $allowed_field_ids ) {
1438 7
				return in_array( $field->ID, $allowed_field_ids, true );
1439 7
			} );
1440
1441 7
			foreach ( array_diff( $allowed_field_ids, wp_list_pluck( $allowed, 'ID' ) ) as $field_id ) {
1442
				$allowed[] = is_numeric( $field_id ) ? \GV\GF_Field::by_id( $view->form, $field_id ) : \GV\Internal_Field::by_id( $field_id );
1443
			}
1444
1445 7
			foreach ( $allowed as $field ) {
1446 7
				$source = is_numeric( $field->ID ) ? $view->form : new \GV\Internal_Source();
1447
1448 7
				$return[] = $renderer->render( $field, $view, $source, $entry, gravityview()->request, '\GV\Field_CSV_Template' );
1449
1450 7
				if ( ! $headers_done ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $headers_done of type false|integer is loosely compared to false; 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...
1451 7
					$label = $field->get_label( $view, $source, $entry );
1452 7
					$headers[] = $label ? $label : $field->ID;
1453
				}
1454
			}
1455
1456 7
			if ( ! $headers_done ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $headers_done of type false|integer is loosely compared to false; 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...
1457 7
				$headers_done = fputcsv( $csv, array_map( array( '\GV\Utils', 'strip_excel_formulas' ), array_values( $headers ) ) );
1458
			}
1459
1460 7
			fputcsv( $csv, array_map( array( '\GV\Utils', 'strip_excel_formulas' ), $return ) );
1461
		}
1462
1463 7
		fflush( $csv );
1464
1465 7
		echo rtrim( ob_get_clean() );
1466
1467 7
		if ( ! defined( 'DOING_GRAVITYVIEW_TESTS' ) ) {
1468
			exit;
1469
		}
1470 7
	}
1471
1472
	/**
1473
	 * Return the query class for this View.
1474
	 *
1475
	 * @return string The class name.
1476
	 */
1477 65
	public function get_query_class() {
1478
		/**
1479
		 * @filter `gravityview/query/class`
1480
		 * @param[in,out] string The query class. Default: GF_Query.
1481
		 * @param \GV\View $this The View.
1482
		 */
1483 65
		$query_class = apply_filters( 'gravityview/query/class', '\GF_Query', $this );
1484 65
		return $query_class;
1485
	}
1486
1487
	/**
1488
	 * Restrict View access to specific capabilities.
1489
	 *
1490
	 * Hooked into `map_meta_cap` WordPress filter.
1491
	 *
1492
	 * @since develop
1493
	 *
1494
	 * @param $caps    array  The output capabilities.
1495
	 * @param $cap     string The cap that is being checked.
1496
	 * @param $user_id int    The User ID.
1497
	 * @param $args    array  Additional arguments to the capability.
1498
	 *
1499
	 * @return array   The resulting capabilities.
1500
	 */
1501 56
	public static function restrict( $caps, $cap, $user_id, $args ) {
1502
		/**
1503
		 * @filter `gravityview/security/require_unfiltered_html` Bypass restrictions on Views that require `unfiltered_html`.
1504
		 * @param[in,out] boolean
1505
		 *
1506
		 * @since develop
1507
		 * @param string $cap The capability requested.
1508
		 * @param int $user_id The user ID.
1509
		 * @param array $args Any additional args to map_meta_cap
1510
		 */
1511 56
		if ( ! apply_filters( 'gravityview/security/require_unfiltered_html', true, $cap, $user_id ) ) {
1512 1
			return $caps;
1513
		}
1514
1515 56
		switch ( $cap ):
1516 56
			case 'edit_gravityview':
1517 56
			case 'edit_gravityviews':
1518 56
			case 'edit_others_gravityviews':
1519 56
			case 'edit_private_gravityviews':
1520 56
			case 'edit_published_gravityviews':
1521 7
				if ( ! user_can( $user_id, 'unfiltered_html' ) ) {
1522 5
					if ( ! user_can( $user_id, 'gravityview_full_access' ) ) {
1523 5
						return array( 'do_not_allow' );
1524
					}
1525
				}
1526
1527 7
				return $caps;
1528 56
			case 'edit_post':
1529 7
				if ( get_post_type( array_pop( $args ) ) == 'gravityview' ) {
1530 6
					return self::restrict( $caps, 'edit_gravityview', $user_id, $args );
1531
				}
1532
		endswitch;
1533
1534 56
		return $caps;
1535
	}
1536
1537 171
	public function __get( $key ) {
1538 171
		if ( $this->post ) {
1539 171
			$raw_post = $this->post->filter( 'raw' );
1540 171
			return $raw_post->{$key};
1541
		}
1542
		return isset( $this->{$key} ) ? $this->{$key} : null;
1543
	}
1544
}
1545