Completed
Push — develop ( 3f4165...c4d58a )
by Gennady
23:31 queued 20:42
created

View::offsetSet()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 3
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
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 168
	public function __construct() {
99 168
		$this->settings = new View_Settings();
100 168
		$this->fields = new Field_Collection();
101 168
		$this->widgets = new Widget_Collection();
102 168
	}
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 'no_direct_access':
293 1
				case 'embed_only':
294 1
				case 'not_public':
295
				default:
296 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() ) );
297 1
					return __( 'You are not allowed to view this content.', 'gravityview' );
298
			}
299
300
			return $content;
301
		}
302
303 6
		$is_admin_and_can_view = $view->settings->get( 'admin_show_all_statuses' ) && \GVCommon::has_cap('gravityview_moderate_entries', $view->ID );
304
305
		/**
306
		 * Editing a single entry.
307
		 */
308 6
		if ( $entry = $request->is_edit_entry( $view->form ? $view->form->ID : 0 ) ) {
309
			if ( $entry['status'] != 'active' ) {
310
				gravityview()->log->notice( 'Entry ID #{entry_id} is not active', array( 'entry_id' => $entry->ID ) );
311
				return __( 'You are not allowed to view this content.', 'gravityview' );
312
			}
313
314
			if ( apply_filters( 'gravityview_custom_entry_slug', false ) && $entry->slug != get_query_var( \GV\Entry::get_endpoint_name() ) ) {
315
				gravityview()->log->error( 'Entry ID #{entry_id} was accessed by a bad slug', array( 'entry_id' => $entry->ID ) );
316
				return __( 'You are not allowed to view this content.', 'gravityview' );
317
			}
318
319
			if ( $view->settings->get( 'show_only_approved' ) && ! $is_admin_and_can_view ) {
320
				if ( ! \GravityView_Entry_Approval_Status::is_approved( gform_get_meta( $entry->ID, \GravityView_Entry_Approval::meta_key ) )  ) {
321
					gravityview()->log->error( 'Entry ID #{entry_id} is not approved for viewing', array( 'entry_id' => $entry->ID ) );
322
					return __( 'You are not allowed to view this content.', 'gravityview' );
323
				}
324
			}
325
326
			$renderer = new Edit_Entry_Renderer();
327
			return $renderer->render( $entry, $view, $request );
328
329
		/**
330
		 * Viewing a single entry.
331
		 */
332 6
		} else if ( $entry = $request->is_entry( $view->form ? $view->form->ID : 0 ) ) {
333
334 2
			$entryset = $entry->is_multi() ? $entry->entries : array( $entry );
335
336 2
			$custom_slug = apply_filters( 'gravityview_custom_entry_slug', false );
337 2
			$ids = explode( ',', get_query_var( \GV\Entry::get_endpoint_name() ) );
338
339 2
			$show_only_approved = $view->settings->get( 'show_only_approved' );
340
341 2
			foreach ( $entryset as $e ) {
342
343 2
				if ( 'active' !== $e['status'] ) {
344 1
					gravityview()->log->notice( 'Entry ID #{entry_id} is not active', array( 'entry_id' => $e->ID ) );
345 1
					return __( 'You are not allowed to view this content.', 'gravityview' );
346
				}
347
348 2
				if ( $custom_slug && ! in_array( $e->slug, $ids ) ) {
349 1
					gravityview()->log->error( 'Entry ID #{entry_id} was accessed by a bad slug', array( 'entry_id' => $e->ID ) );
350 1
					return __( 'You are not allowed to view this content.', 'gravityview' );
351
				}
352
353 2
				if ( $show_only_approved && ! $is_admin_and_can_view ) {
354 1
					if ( ! \GravityView_Entry_Approval_Status::is_approved( gform_get_meta( $e->ID, \GravityView_Entry_Approval::meta_key ) )  ) {
355 1
						gravityview()->log->error( 'Entry ID #{entry_id} is not approved for viewing', array( 'entry_id' => $e->ID ) );
356 1
						return __( 'You are not allowed to view this content.', 'gravityview' );
357
					}
358
				}
359
360 2
				$error = \GVCommon::check_entry_display( $e->as_entry(), $view );
361
362 2
				if ( is_wp_error( $error ) ) {
363 1
					gravityview()->log->error( 'Entry ID #{entry_id} is not approved for viewing: {message}', array( 'entry_id' => $e->ID, 'message' => $error->get_error_message() ) );
364 1
					return __( 'You are not allowed to view this content.', 'gravityview' );
365
				}
366
			}
367
368 2
			$renderer = new Entry_Renderer();
369 2
			return $renderer->render( $entry, $view, $request );
370
		}
371
372
		/**
373
		 * Plain old View.
374
		 */
375 5
		$renderer = new View_Renderer();
376 5
		return $renderer->render( $view, $request );
377
	}
378
379
	/**
380
	 * Checks whether this view can be accessed or not.
381
	 *
382
	 * @param string[]    $context The context we're asking for access from.
383
	 *                             Can any and as many of one of:
384
	 *                                 edit      An edit context.
385
	 *                                 single    A single context.
386
	 *                                 cpt       The custom post type single page acessed.
387
	 *                                 shortcode Embedded as a shortcode.
388
	 *                                 oembed    Embedded as an oEmbed.
389
	 *                                 rest      A REST call.
390
	 * @param \GV\Request $request The request
391
	 *
392
	 * @return bool|\WP_Error An error if this View shouldn't be rendered here.
393
	 */
394 29
	public function can_render( $context = null, $request = null ) {
395 29
		if ( ! $request ) {
396 7
			$request = gravityview()->request;
397
		}
398
399 29
		if ( ! is_array( $context ) ) {
400 6
			$context = array();
401
		}
402
403
		/**
404
		 * @filter `gravityview/view/can_render` Whether the view can be rendered or not.
405
		 * @param bool|\WP_Error $result  The result. Default: null.
406
		 * @param \GV\View       $view	The view.
407
		 * @param string[]       $context See \GV\View::can_render
408
		 * @param \GV\Request    $request The request.
409
		 */
410 29
		if ( ! is_null( $result = apply_filters( 'gravityview/view/can_render', null, $this, $context, $request ) ) ) {
411
			return $result;
412
		}
413
414 29
		if ( in_array( 'rest', $context ) ) {
415
			// REST
416 8
			if ( gravityview()->plugin->settings->get( 'rest_api' ) === '1' && $this->settings->get( 'rest_disable' ) === '1' ) {
417 1
				return new \WP_Error( 'gravityview/rest_disabled' );
418 8
			} elseif ( gravityview()->plugin->settings->get( 'rest_api' ) !== '1' && $this->settings->get( 'rest_enable' ) !== '1' ) {
419 1
				return new \WP_Error( 'gravityview/rest_disabled' );
420
			}
421
		}
422
423 29
		if ( in_array( 'csv', $context ) ) {
424 7
			if ( $this->settings->get( 'csv_enable' ) !== '1' ) {
425 1
				return new \WP_Error( 'gravityview/csv_disabled', 'The CSV endpoint is not enabled for this View' );
426
			}
427
		}
428
429
		/**
430
		 * This View is password protected. Nothing to do here.
431
		 */
432 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...
433 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...
434 3
			return new \WP_Error( 'gravityview/post_password_required' );
435
		}
436
437 29
		if ( ! $this->form ) {
438
			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...
439
			return new \WP_Error( 'gravityview/no_form_attached' );
440
		}
441
442 29
		if ( ! in_array( 'shortcode', $context ) ) {
443
			/**
444
			 * Is this View directly accessible via a post URL?
445
			 *
446
			 * @see https://codex.wordpress.org/Function_Reference/register_post_type#public
447
			 */
448
449
			/**
450
			 * @filter `gravityview_direct_access` Should Views be directly accessible, or only visible using the shortcode?
451
			 * @deprecated
452
			 * @param[in,out] boolean `true`: allow Views to be accessible directly. `false`: Only allow Views to be embedded. Default: `true`
453
			 * @param int $view_id The ID of the View currently being requested. `0` for general setting
454
			 */
455 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...
456
457
			/**
458
			 * @filter `gravityview/request/output/direct` Should this View be directly accessbile?
459
			 * @since 2.0
460
			 * @param[in,out] boolean Accessible or not. Default: accessbile.
461
			 * @param \GV\View $view The View we're trying to directly render here.
462
			 * @param \GV\Request $request The current request.
463
			 */
464 21
			if ( ! apply_filters( 'gravityview/view/output/direct', $direct_access, $this, $request ) ) {
465
				return new \WP_Error( 'gravityview/no_direct_access' );
466
			}
467
468
			/**
469
			 * Is this View an embed-only View? If so, don't allow rendering here,
470
			 *  as this is a direct request.
471
			 */
472 21
			if ( $this->settings->get( 'embed_only' ) && ! \GVCommon::has_cap( 'read_private_gravityviews' ) ) {
473 1
				return new \WP_Error( 'gravityview/embed_only' );
474
			}
475
		}
476
477
		/** Private, pending, draft, etc. */
478 29
		$public_states = get_post_stati( array( 'public' => true ) );
479 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...
480 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...
481 3
			return new \WP_Error( 'gravityview/not_public' );
482
		}
483
484 29
		return true;
485
	}
486
487
	/**
488
	 * Get joins associated with a view
489
	 *
490
	 * @param \WP_Post $post GravityView CPT to get joins for
491
	 *
492
	 * @api
493
	 * @since 2.0.11
494
	 *
495
	 * @return \GV\Join[] Array of \GV\Join instances
496
	 */
497 168
	public static function get_joins( $post ) {
498 168
		$joins = array();
499
500 168
		if ( ! gravityview()->plugin->supports( Plugin::FEATURE_JOINS ) ) {
501
			gravityview()->log->error( 'Cannot get joined forms; joins feature not supported.' );
502
			return $joins;
503
		}
504
505 168
		if ( ! $post || 'gravityview' !== get_post_type( $post ) ) {
506
			gravityview()->log->error( 'Only "gravityview" post types can be \GV\View instances.' );
507
			return $joins;
508
		}
509
510 168
		$joins_meta = get_post_meta( $post->ID, '_gravityview_form_joins', true );
511
512 168
		if ( empty( $joins_meta ) ) {
513 157
			return $joins;
514
		}
515
516 11
		foreach ( $joins_meta as $meta ) {
517 11
			if ( ! is_array( $meta ) || count( $meta ) != 4 ) {
518
				continue;
519
			}
520
521 11
			list( $join, $join_column, $join_on, $join_on_column ) = $meta;
522
523 11
			$join    = GF_Form::by_id( $join );
524 11
			$join_on = GF_Form::by_id( $join_on );
525
526 11
			$join_column    = is_numeric( $join_column ) ? GF_Field::by_id( $join, $join_column ) : Internal_Field::by_id( $join_column );
527 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 );
528
529 11
			$joins [] = new Join( $join, $join_column, $join_on, $join_on_column );
530
		}
531
532 11
		return $joins;
533
	}
534
535
	/**
536
	 * Get joined forms associated with a view
537
	 * In no particular order.
538
	 *
539
	 * @since 2.0.11
540
	 *
541
	 * @api
542
	 * @since 2.0
543
	 * @param int $post_id ID of the View
544
	 *
545
	 * @return \GV\GF_Form[] Array of \GV\GF_Form instances
546
	 */
547 2
	public static function get_joined_forms( $post_id ) {
548 2
		$forms = array();
549
550 2
		if ( ! gravityview()->plugin->supports( Plugin::FEATURE_JOINS ) ) {
551
			gravityview()->log->error( 'Cannot get joined forms; joins feature not supported.' );
552
			return $forms;
553
		}
554
555 2
		if ( ! $post_id || ! gravityview()->plugin->supports( Plugin::FEATURE_JOINS ) ) {
556
			return $forms;
557
		}
558
559 2
		if ( empty( $post_id ) ) {
560
			gravityview()->log->error( 'Cannot get joined forms; $post_id was empty' );
561
			return $forms;
562
		}
563
564 2
		$joins_meta = get_post_meta( $post_id, '_gravityview_form_joins', true );
565
566 2
		if ( empty( $joins_meta ) ) {
567
			return $forms;
568
		}
569
570 2
		foreach ( $joins_meta  as $meta ) {
571 2
			if ( ! is_array( $meta ) || count( $meta ) != 4 ) {
572
				continue;
573
			}
574
575 2
			list( $join, $join_column, $join_on, $join_on_column ) = $meta;
576
577 2
			if ( $form = GF_Form::by_id( $join_on ) ) {
578 2
				$forms[ $join_on ] = $form;
579
			}
580
581 2
			if ( $form = GF_Form::by_id( $join ) ) {
582 2
				$forms[ $join ] = $form;
583
			}
584
		}
585
586 2
		return $forms;
587
	}
588
589
	/**
590
	 * Get unions associated with a view
591
	 *
592
	 * @param \WP_Post $post GravityView CPT to get unions for
593
	 *
594
	 * @api
595
	 * @since 2.2.2
596
	 *
597
	 * @return \GV\Field[][] Array of unions (see self::$unions)
598
	 */
599 168
	public static function get_unions( $post ) {
600 168
		$unions = array();
601
602 168
		if ( ! gravityview()->plugin->supports( Plugin::FEATURE_UNIONS ) ) {
603
			gravityview()->log->error( 'Cannot get unions; unions feature not supported.' );
604
			return $unions;
605
		}
606
607 168
		if ( ! $post || 'gravityview' !== get_post_type( $post ) ) {
608
			gravityview()->log->error( 'Only "gravityview" post types can be \GV\View instances.' );
609
			return $unions;
610
		}
611
612 168
		$fields = get_post_meta( $post->ID, '_gravityview_directory_fields', true );
613
614 168
		if ( empty( $fields ) ) {
615
			return $unions;
616
		}
617
618 168
		foreach ( $fields as $location => $_fields ) {
619 168
			if ( strpos( $location, 'directory_' ) !== 0 ) {
620 47
				continue;
621
			}
622
623 122
			foreach ( $_fields as $field ) {
624 122
				if ( ! empty( $field['unions'] ) ) {
625 1
					foreach ( $field['unions'] as $form_id => $field_id ) {
626 1
						if ( ! isset( $unions[ $form_id ] ) ) {
627 1
							$unions[ $form_id ] = array();
628
						}
629
630 1
						$unions[ $form_id ][ $field['id'] ] =
631 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 );
632
					}
633
				}
634
			}
635
636 122
			break;
637
		}
638
639
		// @todo We'll probably need to backfill null unions
640
641 168
		return $unions;
642
	}
643
644
	/**
645
	 * Construct a \GV\View instance from a \WP_Post.
646
	 *
647
	 * @param \WP_Post $post The \WP_Post instance to wrap.
648
	 *
649
	 * @api
650
	 * @since 2.0
651
	 * @return \GV\View|null An instance around this \WP_Post if valid, null otherwise.
652
	 */
653 169
	public static function from_post( $post ) {
654
655 169
		if ( ! $post || 'gravityview' !== get_post_type( $post ) ) {
656 2
			gravityview()->log->error( 'Only gravityview post types can be \GV\View instances.' );
657 2
			return null;
658
		}
659
660 169
		if ( $view = Utils::get( self::$cache, "View::from_post:{$post->ID}" ) ) {
661
			/**
662
			 * @filter `gravityview/view/get` Override View.
663
			 * @param \GV\View $view The View instance pointer.
664
			 * @since 2.1
665
			 */
666 94
			do_action_ref_array( 'gravityview/view/get', array( &$view ) );
667
668 94
			return $view;
669
		}
670
671 169
		$view = new self();
672 169
		$view->post = $post;
673
674
		/** Get connected form. */
675 169
		$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...
676 169
		if ( ! $view->form ) {
677
			gravityview()->log->error( 'View #{view_id} tried attaching non-existent Form #{form_id} to it.', array(
678
				'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...
679
				'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...
680
			) );
681
		}
682
683 169
		$view->joins = $view::get_joins( $post );
684
685 169
		$view->unions = $view::get_unions( $post );
686
687
		/**
688
		 * @filter `gravityview/configuration/fields` Filter the View fields' configuration array.
689
		 * @since 1.6.5
690
		 *
691
		 * @deprecated Use `gravityview/view/configuration/fields` or `gravityview/view/fields` filters.
692
		 *
693
		 * @param $fields array Multi-array of fields with first level being the field zones.
694
		 * @param $view_id int The View the fields are being pulled for.
695
		 */
696 169
		$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...
697
698
		/**
699
		 * @filter `gravityview/view/configuration/fields` Filter the View fields' configuration array.
700
		 * @since 2.0
701
		 *
702
		 * @param array $fields Multi-array of fields with first level being the field zones.
703
		 * @param \GV\View $view The View the fields are being pulled for.
704
		 */
705 169
		$configuration = apply_filters( 'gravityview/view/configuration/fields', $configuration, $view );
706
707
		/**
708
		 * @filter `gravityview/view/fields` Filter the Field Collection for this View.
709
		 * @since 2.0
710
		 *
711
		 * @param \GV\Field_Collection $fields A collection of fields.
712
		 * @param \GV\View $view The View the fields are being pulled for.
713
		 */
714 169
		$view->fields = apply_filters( 'gravityview/view/fields', Field_Collection::from_configuration( $configuration ), $view );
715
716
		/**
717
		 * @filter `gravityview/view/configuration/widgets` Filter the View widgets' configuration array.
718
		 * @since 2.0
719
		 *
720
		 * @param array $fields Multi-array of widgets with first level being the field zones.
721
		 * @param \GV\View $view The View the widgets are being pulled for.
722
		 */
723 169
		$configuration = apply_filters( 'gravityview/view/configuration/widgets', (array)$view->_gravityview_directory_widgets, $view );
724
725
		/**
726
		 * @filter `gravityview/view/widgets` Filter the Widget Collection for this View.
727
		 * @since 2.0
728
		 *
729
		 * @param \GV\Widget_Collection $widgets A collection of widgets.
730
		 * @param \GV\View $view The View the widgets are being pulled for.
731
		 */
732 169
		$view->widgets = apply_filters( 'gravityview/view/widgets', Widget_Collection::from_configuration( $configuration ), $view );
733
734
		/** View configuration. */
735 169
		$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...
736
737
		/** Add the template name into the settings. */
738 169
		$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...
739
740
		/** View basics. */
741 169
		$view->settings->update( array(
742 169
			'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...
743
		) );
744
745 169
		self::$cache[ "View::from_post:{$post->ID}" ] = &$view;
746
747
		/**
748
		 * @filter `gravityview/view/get` Override View.
749
		 * @param \GV\View $view The View instance pointer.
750
		 * @since 2.1
751
		 */
752 169
		do_action_ref_array( 'gravityview/view/get', array( &$view ) );
753
754 169
		return $view;
755
	}
756
757
	/**
758
	 * Flush the view cache.
759
	 *
760
	 * @param int $view_id The View to reset cache for. Optional. Default: resets everything.
761
	 *
762
	 * @internal
763
	 */
764 183
	public static function _flush_cache( $view_id = null ) {
765 183
		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...
766 177
			unset( self::$cache[ "View::from_post:$view_id" ] );
767 177
			return;
768
		}
769 95
		self::$cache = array();
770 95
	}
771
772
	/**
773
	 * Construct a \GV\View instance from a post ID.
774
	 *
775
	 * @param int|string $post_id The post ID.
776
	 *
777
	 * @api
778
	 * @since 2.0
779
	 * @return \GV\View|null An instance around this \WP_Post or null if not found.
780
	 */
781 107
	public static function by_id( $post_id ) {
782 107
		if ( ! $post_id || ! $post = get_post( $post_id ) ) {
783 3
			return null;
784
		}
785 107
		return self::from_post( $post );
786
	}
787
788
	/**
789
	 * Determines if a view exists to begin with.
790
	 *
791
	 * @param int|\WP_Post|null $view The WordPress post ID, a \WP_Post object or null for global $post;
792
	 *
793
	 * @api
794
	 * @since 2.0
795
	 * @return bool Whether the post exists or not.
796
	 */
797 20
	public static function exists( $view ) {
798 20
		return get_post_type( $view ) == 'gravityview';
799
	}
800
801
	/**
802
	 * ArrayAccess compatibility layer with GravityView_View_Data::$views
803
	 *
804
	 * @internal
805
	 * @deprecated
806
	 * @since 2.0
807
	 * @return bool Whether the offset exists or not, limited to GravityView_View_Data::$views element keys.
808
	 */
809 15
	public function offsetExists( $offset ) {
810 15
		$data_keys = array( 'id', 'view_id', 'form_id', 'template_id', 'atts', 'fields', 'widgets', 'form' );
811 15
		return in_array( $offset, $data_keys );
812
	}
813
814
	/**
815
	 * ArrayAccess compatibility layer with GravityView_View_Data::$views
816
	 *
817
	 * Maps the old keys to the new data;
818
	 *
819
	 * @internal
820
	 * @deprecated
821
	 * @since 2.0
822
	 *
823
	 * @return mixed The value of the requested view data key limited to GravityView_View_Data::$views element keys. If offset not found, return null.
824
	 */
825 15
	public function offsetGet( $offset ) {
826
827 15
		gravityview()->log->notice( 'This is a \GV\View object should not be accessed as an array.' );
828
829 15
		if ( ! isset( $this[ $offset ] ) ) {
830
			return null;
831
		}
832
833 15
		switch ( $offset ) {
834 15
			case 'id':
835 15
			case 'view_id':
836 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...
837 15
			case 'form':
838 15
				return $this->form;
839 1
			case 'form_id':
840 1
				return $this->form ? $this->form->ID : null;
841 1
			case 'atts':
842
				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...
843 1
			case 'template_id':
844 1
				return $this->settings->get( 'template' );
845
			case 'widgets':
846
				return $this->widgets->as_configuration();
847
		}
848
849
		return null;
850
	}
851
852
	/**
853
	 * ArrayAccess compatibility layer with GravityView_View_Data::$views
854
	 *
855
	 * @internal
856
	 * @deprecated
857
	 * @since 2.0
858
	 *
859
	 * @return void
860
	 */
861 1
	public function offsetSet( $offset, $value ) {
862 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.' );
863 1
	}
864
865
	/**
866
	 * ArrayAccess compatibility layer with GravityView_View_Data::$views
867
	 *
868
	 * @internal
869
	 * @deprecated
870
	 * @since 2.0
871
	 * @return void
872
	 */
873 1
	public function offsetUnset( $offset ) {
874 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.' );
875 1
	}
876
877
	/**
878
	 * Be compatible with the old data object.
879
	 *
880
	 * Some external code expects an array (doing things like foreach on this, or array_keys)
881
	 *  so let's return an array in the old format for such cases. Do not use unless using
882
	 *  for back-compatibility.
883
	 *
884
	 * @internal
885
	 * @deprecated
886
	 * @since 2.0
887
	 * @return array
888
	 */
889 23
	public function as_data() {
890
		return array(
891 23
			'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...
892 23
			'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...
893 23
			'form_id' => $this->form ? $this->form->ID : null,
894 23
			'form' => $this->form ? gravityview_get_form( $this->form->ID ) : null,
895 23
			'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...
896 23
			'fields' => $this->fields->by_visible()->as_configuration(),
897 23
			'template_id' => $this->settings->get( 'template' ),
898 23
			'widgets' => $this->widgets->as_configuration(),
899
		);
900
	}
901
902
	/**
903
	 * Retrieve the entries for the current view and request.
904
	 *
905
	 * @param \GV\Request The request. Unused for now.
906
	 *
907
	 * @return \GV\Entry_Collection The entries.
908
	 */
909 65
	public function get_entries( $request = null ) {
910 65
		$entries = new \GV\Entry_Collection();
911 65
		if ( $this->form ) {
912 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...
913
914
			/**
915
			 * Remove multiple sorting before calling legacy filters.
916
			 * This allows us to fake it till we make it.
917
			 */
918 65
			if ( ! empty( $parameters['sort_field'] ) && is_array( $parameters['sort_field'] ) ) {
919 2
				$has_multisort = true;
920 2
				$parameters['sort_field'] = reset( $parameters['sort_field'] );
921 2
				if ( ! empty( $parameters['sort_direction'] ) && is_array( $parameters['sort_direction'] ) ) {
922 2
					$parameters['sort_direction'] = reset( $parameters['sort_direction'] );
923
				}
924
			}
925
926
			/**
927
			 * @todo: Stop using _frontend and use something like $request->get_search_criteria() instead
928
			 */
929 65
			$parameters = \GravityView_frontend::get_view_entries_parameters( $parameters, $this->form->ID );
930 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...
931 65
			$parameters = \GVCommon::calculate_get_entries_criteria( $parameters, $this->form->ID );
932
933 65
			if ( $request instanceof REST\Request ) {
934 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...
935 6
				$paging_parameters = wp_parse_args( $request->get_paging(), array(
936 6
						'paging' => array( 'page_size' => $atts['page_size'] ),
937
					) );
938 6
				$parameters['paging'] = $paging_parameters['paging'];
939
			}
940
941 65
			$page = Utils::get( $parameters['paging'], 'current_page' ) ?
942 65
				: ( ( ( $parameters['paging']['offset'] - $this->settings->get( 'offset' ) ) / $parameters['paging']['page_size'] ) + 1 );
943
944
			/**
945
			 * Cleanup duplicate field_filter parameters to simplify the query.
946
			 */
947 65
			$unique_field_filters = array();
948 65
			foreach ( $parameters['search_criteria']['field_filters'] as $key => $filter ) {
949 11
				if ( 'mode' === $key ) {
950 10
					$unique_field_filters['mode'] = $filter;
951 11
				} else if ( ! in_array( $filter, $unique_field_filters ) ) {
952 11
					$unique_field_filters[] = $filter;
953
				}
954
			}
955 65
			$parameters['search_criteria']['field_filters'] = $unique_field_filters;
956
957 65
			if ( ! empty( $parameters['search_criteria']['field_filters'] ) ) {
958 11
				gravityview()->log->notice( 'search_criteria/field_filters is not empty, third-party code may be using legacy search_criteria filters.' );
959
			}
960
961 65
			if ( gravityview()->plugin->supports( Plugin::FEATURE_GFQUERY ) ) {
962
963 65
				$query_class = $this->get_query_class();
964
965
				/** @var \GF_Query $query */
966 65
				$query = new $query_class( $this->form->ID, $parameters['search_criteria'], $parameters['sorting'] );
967
968
				/**
969
				 * Apply multisort.
970
				 */
971 65
				if ( ! empty( $has_multisort ) ) {
972 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...
973
974 2
					$view_setting_sort_field_ids = \GV\Utils::get( $atts, 'sort_field', array() );
975 2
					$view_setting_sort_directions = \GV\Utils::get( $atts, 'sort_direction', array() );
976
977 2
					$has_sort_query_param = ! empty( $_GET['sort'] ) && is_array( $_GET['sort'] );
978
979 2
					if( $has_sort_query_param ) {
980
						$has_sort_query_param = array_filter( array_values( $_GET['sort'] ) );
981
					}
982
983 2
					if ( $this->settings->get( 'sort_columns' ) && $has_sort_query_param ) {
984
						$sort_field_ids = array_keys( $_GET['sort'] );
985
						$sort_directions = array_values( $_GET['sort'] );
986
					} else {
987 2
						$sort_field_ids = $view_setting_sort_field_ids;
988 2
						$sort_directions = $view_setting_sort_directions;
989
					}
990
991 2
					$skip_first = false;
992
993 2
					foreach ( (array) $sort_field_ids as $key => $sort_field_id ) {
994
995 2
						if ( ! $skip_first && ! $has_sort_query_param ) {
996 2
							$skip_first = true; // Skip the first one, it's already in the query
997 2
							continue;
998
						}
999
1000 1
						$sort_field_id = \GravityView_frontend::_override_sorting_id_by_field_type( $sort_field_id, $this->form->ID );
1001 1
						$sort_direction = strtoupper( \GV\Utils::get( $sort_directions, $key, 'ASC' ) );
1002
1003 1
						if ( ! empty( $sort_field_id ) ) {
1004 1
							$order = new \GF_Query_Column( $sort_field_id, $this->form->ID );
1005 1
							if ( \GVCommon::is_field_numeric( $this->form->ID, $sort_field_id ) ) {
1006
								$order = \GF_Query_Call::CAST( $order, defined( 'GF_Query::TYPE_DECIMAL' ) ? \GF_Query::TYPE_DECIMAL : \GF_Query::TYPE_SIGNED );
1007
							}
1008
1009 1
							$query->order( $order, $sort_direction );
1010
						}
1011
					}
1012
				}
1013
1014
				/**
1015
				 * Merge time subfield sorts.
1016
				 */
1017 65
				add_filter( 'gform_gf_query_sql', $gf_query_timesort_sql_callback = function( $sql ) use ( &$query ) {
1018 65
					$q = $query->_introspect();
1019 65
					$orders = array();
1020
1021 65
					$merged_time = false;
1022
1023 65
					foreach ( $q['order'] as $oid => $order ) {
1024 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...
1025 64
							$column = $order[0];
1026 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...
1027 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...
1028
								$orders[ $oid ] = $order;
1029
								continue; // Need something that resembles a single sort
1030
							}
1031 1
							$column = $order[0]->columns[0];
1032
						}
1033
1034 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...
1035 64
							$orders[ $oid ] = $order;
1036 64
							continue; // Not a time field
1037
						}
1038
1039 1
						if ( ! class_exists( '\GV\Mocks\GF_Query_Call_TIMESORT' ) ) {
1040 1
							require_once gravityview()->plugin->dir( 'future/_mocks.timesort.php' );
1041
						}
1042
1043 1
						$orders[ $oid ] = array(
1044 1
							new \GV\Mocks\GF_Query_Call_TIMESORT( 'timesort', array( $column, $sql ) ),
1045 1
							$order[1] // Mock it!
1046
						);
1047
1048 1
						$merged_time = true;
1049
					}
1050
1051 65
					if ( $merged_time ) {
1052
						/**
1053
						 * ORDER again.
1054
						 */
1055 1
						if ( ! empty( $orders ) && $_orders = $query->_order_generate( $orders ) ) {
1056 1
							$sql['order'] = 'ORDER BY ' . implode( ', ', $_orders );
1057
						}
1058
					}
1059
1060 65
					return $sql;
1061 65
				} );
1062
1063 65
				$query->limit( $parameters['paging']['page_size'] )
1064 65
					->offset( ( ( $page - 1 ) * $parameters['paging']['page_size'] ) + $this->settings->get( 'offset' ) );
1065
1066
				/**
1067
				 * Any joins?
1068
				 */
1069 65
				if ( gravityview()->plugin->supports( Plugin::FEATURE_JOINS ) && count( $this->joins ) ) {
1070
1071 11
					$is_admin_and_can_view = $this->settings->get( 'admin_show_all_statuses' ) && \GVCommon::has_cap( 'gravityview_moderate_entries', $this->ID );
1072
1073 11
					foreach ( $this->joins as $join ) {
1074 11
						$query = $join->as_query_join( $query );
1075
1076 11
						if ( $this->settings->get( 'multiple_forms_disable_null_joins' ) ) {
1077
1078
							// Disable NULL outputs
1079
							$condition = new \GF_Query_Condition(
1080
								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...
1081
								\GF_Query_Condition::NEQ,
1082
								new \GF_Query_Literal( '' )
1083
							);
1084
1085
							$query_parameters = $query->_introspect();
1086
1087
							$query->where( \GF_Query_Condition::_and( $query_parameters['where'], $condition ) );
1088
						}
1089
1090
						/**
1091
						 * This is a temporary stub filter, until GF_Query supports NULL conditions.
1092
						 * Do not use! This filter will be removed.
1093
						 */
1094 11
						if ( defined( 'GF_Query_Condition::NULL' ) ) {
1095 11
							$is_null_condition_native = true;
1096
						} else {
1097
							$is_null_condition_class = apply_filters( 'gravityview/query/is_null_condition', null );
1098
							$is_null_condition_native = false;
1099
						}
1100
1101
						// Filter to active entries only
1102 11
						$condition = new \GF_Query_Condition(
1103 11
							new \GF_Query_Column( 'status', $join->join_on->ID ),
1104 11
							\GF_Query_Condition::EQ,
1105 11
							new \GF_Query_Literal( 'active' )
1106
						);
1107
1108 11
						if ( $is_null_condition_native ) {
1109 11
							$condition = \GF_Query_Condition::_or( $condition, new \GF_Query_Condition(
1110 11
								new \GF_Query_Column( 'status', $join->join_on->ID ),
1111 11
								\GF_Query_Condition::IS,
1112 11
								\GF_Query_Condition::NULL
1113
							) );
1114
						} else if ( ! is_null( $is_null_condition_class ) ) {
1115
							$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...
1116
								new \GF_Query_Column( 'status', $join->join_on->ID )
1117
							) );
1118
						}
1119
1120 11
						$q = $query->_introspect();
1121 11
						$query->where( \GF_Query_Condition::_and( $q['where'], $condition ) );
1122
1123 11
						if ( $this->settings->get( 'show_only_approved' ) && ! $is_admin_and_can_view ) {
1124
1125
							// Show only approved joined entries
1126 1
							$condition = new \GF_Query_Condition(
1127 1
								new \GF_Query_Column( \GravityView_Entry_Approval::meta_key, $join->join_on->ID ),
1128 1
								\GF_Query_Condition::EQ,
1129 1
								new \GF_Query_Literal( \GravityView_Entry_Approval_Status::APPROVED )
1130
							);
1131
1132 1
							if ( $is_null_condition_native ) {
1133 1
								$condition = \GF_Query_Condition::_or( $condition, new \GF_Query_Condition(
1134 1
									new \GF_Query_Column( \GravityView_Entry_Approval::meta_key, $join->join_on->ID ),
1135 1
									\GF_Query_Condition::IS,
1136 1
									\GF_Query_Condition::NULL
1137
								) );
1138
							} else if ( ! is_null( $is_null_condition_class ) ) {
1139
								$condition = \GF_Query_Condition::_or( $condition, new $is_null_condition_class(
1140
									new \GF_Query_Column( \GravityView_Entry_Approval::meta_key, $join->join_on->ID )
1141
								) );
1142
							}
1143
1144 1
							$query_parameters = $query->_introspect();
1145
1146 1
							$query->where( \GF_Query_Condition::_and( $query_parameters['where'], $condition ) );
1147
						}
1148
					}
1149
				
1150
				/**
1151
				 * Unions?
1152
				 */
1153 54
				} else if ( gravityview()->plugin->supports( Plugin::FEATURE_UNIONS ) && count( $this->unions ) ) {
1154 1
					$query_parameters = $query->_introspect();
1155
1156 1
					$unions_sql = array();
1157
1158
					/**
1159
					 * @param \GF_Query_Condition $condition
1160
					 * @param array $fields
1161
					 * @param $recurse
1162
					 *
1163
					 * @return \GF_Query_Condition
1164
					 */
1165 1
					$where_union_substitute = function( $condition, $fields, $recurse ) {
1166 1
						if ( $condition->expressions ) {
1167 1
							$conditions = array();
1168
1169 1
							foreach ( $condition->expressions as $_condition ) {
1170 1
								$conditions[] = $recurse( $_condition, $fields, $recurse );
1171
							}
1172
1173 1
							return call_user_func_array(
1174 1
								array( '\GF_Query_Condition', $condition->operator == 'AND' ? '_and' : '_or' ),
1175 1
								$conditions
1176
							);
1177
						}
1178
1179 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...
1180 1
							return new \GF_Query_Condition(
1181 1
								new \GF_Query_Column( $fields[ $condition->left->field_id ]->ID ),
1182 1
								$condition->operator,
1183 1
								$condition->right
1184
							);
1185
						}
1186
1187 1
						return $condition;
1188 1
					};
1189
1190 1
					foreach ( $this->unions as $form_id => $fields ) {
1191
1192
						// Build a new query for every unioned form
1193 1
						$query_class = $this->get_query_class();
1194
1195
						/** @var \GF_Query|\GF_Patched_Query $q */
1196 1
						$q = new $query_class( $form_id );
1197
1198
						// Copy the WHERE clauses but substitute the field_ids to the respective ones
1199 1
						$q->where( $where_union_substitute( $query_parameters['where'], $fields, $where_union_substitute ) );
1200
1201
						// Copy the ORDER clause and substitute the field_ids to the respective ones
1202 1
						foreach ( $query_parameters['order'] as $order ) {
1203 1
							list( $column, $_order ) = $order;
1204
1205 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...
1206 1
								if ( ! $column->is_entry_column() && ! $column->is_meta_column() ) {
1207 1
									$column = new \GF_Query_Column( $fields[ $column->field_id ]->ID );
1208
								}
1209
1210 1
								$q->order( $column, $_order );
1211
							}
1212
						}
1213
1214 1
						add_filter( 'gform_gf_query_sql', $gf_query_sql_callback = function( $sql ) use ( &$unions_sql ) {
1215
							// Remove SQL_CALC_FOUND_ROWS as it's not needed in UNION clauses
1216 1
							$select = 'UNION ALL ' . str_replace( 'SQL_CALC_FOUND_ROWS ', '', $sql['select'] );
1217
1218
							// Record the SQL
1219 1
							$unions_sql[] = array(
1220
								// Remove columns, we'll rebuild them
1221 1
								'select'  => preg_replace( '#DISTINCT (.*)#', 'DISTINCT ', $select ),
1222 1
								'from'    => $sql['from'],
1223 1
								'join'    => $sql['join'],
1224 1
								'where'   => $sql['where'],
1225
								// Remove order and limit
1226
							);
1227
1228
							// Return empty query, no need to call the database
1229 1
							return array();
1230 1
						} );
1231
1232 1
						do_action_ref_array( 'gravityview/view/query', array( &$q, $this, $request ) );
1233
1234 1
						$q->get(); // Launch
1235
1236 1
						remove_filter( 'gform_gf_query_sql', $gf_query_sql_callback );
1237
					}
1238
1239 1
					add_filter( 'gform_gf_query_sql', $gf_query_sql_callback = function( $sql ) use ( $unions_sql ) {
1240
						// Remove SQL_CALC_FOUND_ROWS as it's not needed in UNION clauses
1241 1
						$sql['select'] = str_replace( 'SQL_CALC_FOUND_ROWS ', '', $sql['select'] );
1242
1243
						// Remove columns, we'll rebuild them
1244 1
						preg_match( '#DISTINCT (`[motc]\d+`.`.*?`)#', $sql['select'], $select_match );
1245 1
						$sql['select'] = preg_replace( '#DISTINCT (.*)#', 'DISTINCT ', $sql['select'] );
1246
1247 1
						$unions = array();
1248
1249
						// Transform selected columns to shared alias names
1250 1
						$column_to_alias = function( $column ) {
1251 1
							$column = str_replace( '`', '', $column );
1252 1
							return '`' . str_replace( '.', '_', $column ) . '`';
1253 1
						};
1254
1255
						// Add all the order columns into the selects, so we can order by the whole union group
1256 1
						preg_match_all( '#(`[motc]\d+`.`.*?`)#', $sql['order'], $order_matches );
1257
						
1258
						$columns = array(
1259 1
							sprintf( '%s AS %s', $select_match[1], $column_to_alias( $select_match[1] ) )
1260
						);
1261
1262 1
						foreach ( array_slice( $order_matches, 1 ) as $match ) {
1263 1
							$columns[] = sprintf( '%s AS %s', $match[0], $column_to_alias( $match[0] ) );
1264
1265
							// Rewrite the order columns to the shared aliases
1266 1
							$sql['order'] = str_replace( $match[0], $column_to_alias( $match[0] ), $sql['order'] );
1267
						}
1268
1269 1
						$columns = array_unique( $columns );
1270
1271
						// Add the columns to every UNION
1272 1
						foreach ( $unions_sql as $union_sql ) {
1273 1
							$union_sql['select'] .= implode( ', ', $columns );
1274 1
							$unions []= implode( ' ', $union_sql );
1275
						}
1276
1277
						// Add the columns to the main SELECT, but only grab the entry id column
1278 1
						$sql['select'] = 'SELECT SQL_CALC_FOUND_ROWS t1_id FROM (' . $sql['select'] . implode( ', ', $columns );
1279 1
						$sql['order'] = implode( ' ', $unions ) . ') AS u ' . $sql['order'];
1280
1281 1
						return $sql;
1282 1
					} );
1283
				}
1284
1285
				/**
1286
				 * @action `gravityview/view/query` Override the \GF_Query before the get() call.
1287
				 * @param \GF_Query $query The current query object reference
1288
				 * @param \GV\View $this The current view object
1289
				 * @param \GV\Request $request The request object
1290
				 */
1291 65
				do_action_ref_array( 'gravityview/view/query', array( &$query, $this, $request ) );
1292
1293 65
				gravityview()->log->debug( 'GF_Query parameters: ', array( 'data' => Utils::gf_query_debug( $query ) ) );
1294
1295
				/**
1296
				 * Map from Gravity Forms entries arrays to an Entry_Collection.
1297
				 */
1298 65
				if ( count( $this->joins ) ) {
1299 11
					foreach ( $query->get() as $entry ) {
1300 11
						$entries->add(
1301 11
							Multi_Entry::from_entries( array_map( '\GV\GF_Entry::from_entry', $entry ) )
1302
						);
1303
					}
1304
				} else {
1305 54
					array_map( array( $entries, 'add' ), array_map( '\GV\GF_Entry::from_entry', $query->get() ) );
1306
				}
1307
1308 65
				if ( isset( $gf_query_sql_callback ) ) {
1309 1
					remove_action( 'gform_gf_query_sql', $gf_query_sql_callback );
1310
				}
1311
1312 65
				if ( isset( $gf_query_timesort_sql_callback ) ) {
1313 65
					remove_action( 'gform_gf_query_sql', $gf_query_timesort_sql_callback );
1314
				}
1315
1316
				/**
1317
				 * Add total count callback.
1318
				 */
1319 65
				$entries->add_count_callback( function() use ( $query ) {
1320 31
					return $query->total_found;
1321 65
				} );
1322
			} else {
1323
				$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...
1324
					->filter( \GV\GF_Entry_Filter::from_search_criteria( $parameters['search_criteria'] ) )
1325
					->offset( $this->settings->get( 'offset' ) )
1326
					->limit( $parameters['paging']['page_size'] )
1327
					->page( $page );
1328
1329
				if ( ! empty( $parameters['sorting'] ) && is_array( $parameters['sorting'] && ! isset( $parameters['sorting']['key'] ) ) ) {
1330
					// Pluck off multisort arrays
1331
					$parameters['sorting'] = $parameters['sorting'][0];
1332
				}
1333
1334
				if ( ! empty( $parameters['sorting'] ) && ! empty( $parameters['sorting']['key'] ) ) {
1335
					$field = new \GV\Field();
1336
					$field->ID = $parameters['sorting']['key'];
1337
					$direction = strtolower( $parameters['sorting']['direction'] ) == 'asc' ? \GV\Entry_Sort::ASC : \GV\Entry_Sort::DESC;
1338
					$entries = $entries->sort( new \GV\Entry_Sort( $field, $direction ) );
1339
				}
1340
			}
1341
		}
1342
1343
		/**
1344
		 * @filter `gravityview/view/entries` Modify the entry fetching filters, sorts, offsets, limits.
1345
		 * @param \GV\Entry_Collection $entries The entries for this view.
1346
		 * @param \GV\View $view The view.
1347
		 * @param \GV\Request $request The request.
1348
		 */
1349 65
		return apply_filters( 'gravityview/view/entries', $entries, $this, $request );
1350
	}
1351
1352
	/**
1353
	 * Last chance to configure the output.
1354
	 *
1355
	 * Used for CSV output, for example.
1356
	 *
1357
	 * @return void
1358
	 */
1359 7
	public static function template_redirect() {
1360
		/**
1361
		 * CSV output.
1362
		 */
1363 7
		if ( ! get_query_var( 'csv' ) ) {
1364 1
			return;
1365
		}
1366
1367 7
		if ( ! $view = gravityview()->request->is_view() ) {
1368 1
			return;
1369
		}
1370
1371 7
		if ( is_wp_error( $error = $view->can_render( array( 'csv' ) ) ) ) {
1372 1
			gravityview()->log->error( 'Not rendering CSV: ' . $error->get_error_message() );
1373 1
			return;
1374
		}
1375
1376
		/**
1377
		 * Modify the name of the generated CSV file. Name will be sanitized using sanitize_file_name() before output.
1378
		 * @see sanitize_file_name()
1379
		 * @since 2.1
1380
		 * @param string   $filename File name used when downloading a CSV. Default is "{View title}.csv"
1381
		 * @param \GV\View $view Current View being rendered
1382
		 */
1383 7
		$filename = apply_filters( 'gravityview/output/csv/filename', get_the_title( $view->post ), $view );
1384
1385 7
		if ( ! defined( 'DOING_GRAVITYVIEW_TESTS' ) ) {
1386
			header( sprintf( 'Content-Disposition: attachment;filename="%s.csv"', sanitize_file_name( $filename ) ) );
1387
			header( 'Content-Transfer-Encoding: binary' );
1388
			header( 'Content-Type: text/csv' );
1389
		}
1390
1391 7
		ob_start();
1392 7
		$csv = fopen( 'php://output', 'w' );
1393
1394
		/**
1395
		 * Add da' BOM if GF uses it
1396
		 * @see GFExport::start_export()
1397
		 */
1398 7
		if ( apply_filters( 'gform_include_bom_export_entries', true, $view->form ? $view->form->form : null ) ) {
1399
			fputs( $csv, "\xef\xbb\xbf" );
1400
		}
1401
1402 7
		if ( $view->settings->get( 'csv_nolimit' ) ) {
1403 1
			$view->settings->update( array( 'page_size' => -1 ) );
1404
		}
1405
1406 7
		$entries = $view->get_entries();
1407
1408 7
		$headers_done = false;
1409 7
		$allowed = $headers = array();
1410
1411 7
		foreach ( $view->fields->by_position( "directory_*" )->by_visible()->all() as $id => $field ) {
1412 7
			$allowed[] = $field;
1413
		}
1414
1415 7
		$renderer = new Field_Renderer();
1416
1417 7
		foreach ( $entries->all() as $entry ) {
1418
1419 7
			$return = array();
1420
1421
			/**
1422
			 * @filter `gravityview/csv/entry/fields` Whitelist more entry fields by ID that are output in CSV requests.
1423
			 * @param[in,out] array $allowed The allowed ones, default by_visible, by_position( "context_*" ), i.e. as set in the View.
1424
			 * @param \GV\View $view The view.
1425
			 * @param \GV\Entry $entry WordPress representation of the item.
1426
			 */
1427 7
			$allowed_field_ids = apply_filters( 'gravityview/csv/entry/fields', wp_list_pluck( $allowed, 'ID' ), $view, $entry );
1428
1429 7
			$allowed = array_filter( $allowed, function( $field ) use ( $allowed_field_ids ) {
1430 7
				return in_array( $field->ID, $allowed_field_ids, true );
1431 7
			} );
1432
1433 7
			foreach ( array_diff( $allowed_field_ids, wp_list_pluck( $allowed, 'ID' ) ) as $field_id ) {
1434
				$allowed[] = is_numeric( $field_id ) ? \GV\GF_Field::by_id( $view->form, $field_id ) : \GV\Internal_Field::by_id( $field_id );
1435
			}
1436
1437 7
			foreach ( $allowed as $field ) {
1438 7
				$source = is_numeric( $field->ID ) ? $view->form : new \GV\Internal_Source();
1439
1440 7
				$return[] = $renderer->render( $field, $view, $source, $entry, gravityview()->request, '\GV\Field_CSV_Template' );
1441
1442 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...
1443 7
					$label = $field->get_label( $view, $source, $entry );
1444 7
					$headers[] = $label ? $label : $field->ID;
1445
				}
1446
			}
1447
1448 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...
1449 7
				$headers_done = fputcsv( $csv, array_map( array( '\GV\Utils', 'strip_excel_formulas' ), array_values( $headers ) ) );
1450
			}
1451
1452 7
			fputcsv( $csv, array_map( array( '\GV\Utils', 'strip_excel_formulas' ), $return ) );
1453
		}
1454
1455 7
		fflush( $csv );
1456
1457 7
		echo rtrim( ob_get_clean() );
1458
1459 7
		if ( ! defined( 'DOING_GRAVITYVIEW_TESTS' ) ) {
1460
			exit;
1461
		}
1462 7
	}
1463
1464
	/**
1465
	 * Return the query class for this View.
1466
	 *
1467
	 * @return string The class name.
1468
	 */
1469 65
	public function get_query_class() {
1470
		/**
1471
		 * @filter `gravityview/query/class`
1472
		 * @param[in,out] string The query class. Default: GF_Query.
1473
		 * @param \GV\View $this The View.
1474
		 */
1475 65
		$query_class = apply_filters( 'gravityview/query/class', '\GF_Query', $this );
1476 65
		return $query_class;
1477
	}
1478
1479
	/**
1480
	 * Restrict View access to specific capabilities.
1481
	 *
1482
	 * Hooked into `map_meta_cap` WordPress filter.
1483
	 *
1484
	 * @since develop
1485
	 *
1486
	 * @param $caps    array  The output capabilities.
1487
	 * @param $cap     string The cap that is being checked.
1488
	 * @param $user_id int    The User ID.
1489
	 * @param $args    array  Additional arguments to the capability.
1490
	 *
1491
	 * @return array   The resulting capabilities.
1492
	 */
1493 53
	public static function restrict( $caps, $cap, $user_id, $args ) {
1494
		/**
1495
		 * @filter `gravityview/security/require_unfiltered_html` Bypass restrictions on Views that require `unfiltered_html`.
1496
		 * @param[in,out] boolean
1497
		 *
1498
		 * @since develop
1499
		 * @param string $cap The capability requested.
1500
		 * @param int $user_id The user ID.
1501
		 * @param array $args Any additional args to map_meta_cap
1502
		 */
1503 53
		if ( ! apply_filters( 'gravityview/security/require_unfiltered_html', true, $cap, $user_id ) ) {
1504 1
			return $caps;
1505
		}
1506
1507 53
		switch ( $cap ):
1508 53
			case 'edit_gravityview':
1509 53
			case 'edit_gravityviews':
1510 53
			case 'edit_others_gravityviews':
1511 53
			case 'edit_private_gravityviews':
1512 53
			case 'edit_published_gravityviews':
1513 7
				if ( ! user_can( $user_id, 'unfiltered_html' ) ) {
1514 5
					if ( ! user_can( $user_id, 'gravityview_full_access' ) ) {
1515 5
						return array( 'do_not_allow' );
1516
					}
1517
				}
1518
1519 7
				return $caps;
1520 53
			case 'edit_post':
1521 7
				if ( get_post_type( array_pop( $args ) ) == 'gravityview' ) {
1522 6
					return self::restrict( $caps, 'edit_gravityview', $user_id, $args );
1523
				}
1524
		endswitch;
1525
1526 53
		return $caps;
1527
	}
1528
1529 168
	public function __get( $key ) {
1530 168
		if ( $this->post ) {
1531 168
			$raw_post = $this->post->filter( 'raw' );
1532 168
			return $raw_post->{$key};
1533
		}
1534
		return isset( $this->{$key} ) ? $this->{$key} : null;
1535
	}
1536
}
1537