Complex classes like gravityview often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use gravityview, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
12 | class gravityview extends \GV\Shortcode { |
||
13 | /** |
||
14 | * {@inheritDoc} |
||
15 | */ |
||
16 | public $name = 'gravityview'; |
||
17 | |||
18 | /** |
||
19 | * Process and output the [gravityview] shortcode. |
||
20 | * |
||
21 | * @param array $passed_atts The attributes passed. |
||
22 | * @param string $content The content inside the shortcode. |
||
23 | * |
||
24 | * @return string|null The output. |
||
25 | */ |
||
26 | 6 | public function callback( $passed_atts, $content = null ) { |
|
27 | |||
28 | 6 | $request = gravityview()->request; |
|
29 | |||
30 | 6 | if ( $request->is_admin() ) { |
|
31 | return ''; |
||
32 | } |
||
33 | |||
34 | 6 | $atts = wp_parse_args( $passed_atts, array( |
|
35 | 6 | 'id' => 0, |
|
36 | 'view_id' => 0, |
||
37 | 'detail' => null, |
||
38 | ) ); |
||
39 | |||
40 | 6 | if ( ! $view_id = $atts['id'] ? : $atts['view_id'] ) { |
|
41 | if ( $atts['detail'] && $view = $request->is_view() ) { |
||
42 | $view_id = $view->ID; |
||
43 | } |
||
44 | } |
||
45 | |||
46 | 6 | $view = \GV\View::by_id( $view_id ); |
|
47 | |||
48 | 6 | if ( ! $view ) { |
|
49 | gravityview()->log->error( 'View does not exist #{view_id}', array( 'view_id' => $view_id ) ); |
||
50 | return ''; |
||
51 | } |
||
52 | |||
53 | 6 | gravityview()->views->set( $view ); |
|
54 | |||
55 | /** |
||
56 | * When this shortcode is embedded inside a View we can only display it as a directory. There's no other way. |
||
57 | * Try to detect that we're not embedded to allow edit and single contexts. |
||
58 | */ |
||
59 | 6 | $is_reembedded = false; // Assume not embedded unless detected otherwise. |
|
60 | 6 | if ( in_array( get_class( $request ), array( 'GV\Frontend_Request', 'GV\Mock_Request' ) ) ) { |
|
61 | 6 | if ( ( $_view = $request->is_view() ) && $_view->ID !== $view->ID ) { |
|
62 | $is_reembedded = true; |
||
63 | } |
||
64 | } |
||
65 | |||
66 | /** |
||
67 | * Remove Widgets on a nested embedded View. |
||
68 | */ |
||
69 | 6 | if ( $is_reembedded ) { |
|
70 | $view->widgets = new \GV\Widget_Collection(); |
||
71 | } |
||
72 | |||
73 | 6 | $atts = $this->parse_and_sanitize_atts( $atts ); |
|
74 | |||
75 | 6 | $view->settings->update( $atts ); |
|
76 | 6 | $entries = $view->get_entries( $request ); |
|
77 | |||
78 | /** |
||
79 | * Check permissions. |
||
80 | */ |
||
81 | 6 | while ( $error = $view->can_render( array( 'shortcode' ), $request ) ) { |
|
82 | 1 | if ( ! is_wp_error( $error ) ) |
|
83 | break; |
||
84 | |||
85 | 1 | switch ( str_replace( 'gravityview/', '', $error->get_error_code() ) ) { |
|
86 | 1 | case 'post_password_required': |
|
87 | 1 | return get_the_password_form( $view->ID ); |
|
88 | 1 | case 'no_form_attached': |
|
89 | /** |
||
90 | * This View has no data source. There's nothing to show really. |
||
91 | * ...apart from a nice message if the user can do anything about it. |
||
92 | */ |
||
93 | if ( \GVCommon::has_cap( array( 'edit_gravityviews', 'edit_gravityview' ), $view->ID ) ) { |
||
94 | 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' ); |
||
95 | } |
||
96 | break; |
||
97 | 1 | case 'no_direct_access': |
|
98 | 1 | case 'embed_only': |
|
99 | 1 | case 'not_public': |
|
100 | 1 | return __( 'You are not allowed to view this content.', 'gravityview' ); |
|
101 | } |
||
102 | } |
||
103 | |||
104 | 6 | $is_admin_and_can_view = $view->settings->get( 'admin_show_all_statuses' ) && \GVCommon::has_cap('gravityview_moderate_entries', $view->ID ); |
|
105 | |||
106 | /** |
||
107 | * View details. |
||
108 | */ |
||
109 | 6 | if ( $atts['detail'] ) { |
|
110 | 2 | return $this->detail( $view, $entries, $atts ); |
|
111 | |||
112 | /** |
||
113 | * Editing a single entry. |
||
114 | */ |
||
115 | 5 | } else if ( ! $is_reembedded && ( $entry = $request->is_edit_entry() ) ) { |
|
116 | |||
117 | /** |
||
118 | * When editing an entry don't render multiple views. |
||
119 | */ |
||
120 | if ( ( $selected = \GV\Utils::_GET( 'gvid' ) ) && $view->ID != $selected ) { |
||
121 | gravityview()->log->notice( 'Entry ID #{entry_id} not rendered because another View ID was passed using `?gvid`: #{selected}', array( 'entry_id' => $entry->ID, 'selected' => $selected ) ); |
||
122 | return ''; |
||
123 | } |
||
124 | |||
125 | if ( $entry['status'] != 'active' ) { |
||
126 | gravityview()->log->notice( 'Entry ID #{entry_id} is not active', array( 'entry_id' => $entry->ID ) ); |
||
127 | return __( 'You are not allowed to view this content.', 'gravityview' ); |
||
128 | } |
||
129 | |||
130 | if ( apply_filters( 'gravityview_custom_entry_slug', false ) && $entry->slug != get_query_var( \GV\Entry::get_endpoint_name() ) ) { |
||
131 | gravityview()->log->error( 'Entry ID #{entry_id} was accessed by a bad slug', array( 'entry_id' => $entry->ID ) ); |
||
132 | return __( 'You are not allowed to view this content.', 'gravityview' ); |
||
133 | } |
||
134 | |||
135 | if ( $view->settings->get( 'show_only_approved' ) && ! $is_admin_and_can_view ) { |
||
136 | if ( ! \GravityView_Entry_Approval_Status::is_approved( gform_get_meta( $entry->ID, \GravityView_Entry_Approval::meta_key ) ) ) { |
||
137 | gravityview()->log->error( 'Entry ID #{entry_id} is not approved for viewing', array( 'entry_id' => $entry->ID ) ); |
||
138 | return __( 'You are not allowed to view this content.', 'gravityview' ); |
||
139 | } |
||
140 | } |
||
141 | |||
142 | $renderer = new \GV\Edit_Entry_Renderer(); |
||
143 | return $renderer->render( $entry, $view, $request ); |
||
144 | |||
145 | /** |
||
146 | * Viewing a single entry. |
||
147 | */ |
||
148 | 5 | } else if ( ! $is_reembedded && ( $entry = $request->is_entry() ) ) { |
|
149 | /** |
||
150 | * When viewing an entry don't render multiple views. |
||
151 | */ |
||
152 | 2 | if ( ( $selected = \GV\Utils::_GET( 'gvid' ) ) && $view->ID != $selected ) { |
|
153 | return ''; |
||
154 | } |
||
155 | |||
156 | 2 | if ( $entry['status'] != 'active' ) { |
|
157 | 1 | gravityview()->log->notice( 'Entry ID #{entry_id} is not active', array( 'entry_id' => $entry->ID ) ); |
|
158 | 1 | return __( 'You are not allowed to view this content.', 'gravityview' ); |
|
159 | } |
||
160 | |||
161 | 2 | if ( apply_filters( 'gravityview_custom_entry_slug', false ) && $entry->slug != get_query_var( \GV\Entry::get_endpoint_name() ) ) { |
|
162 | 1 | gravityview()->log->error( 'Entry ID #{entry_id} was accessed by a bad slug', array( 'entry_id' => $entry->ID ) ); |
|
163 | 1 | return __( 'You are not allowed to view this content.', 'gravityview' ); |
|
164 | } |
||
165 | |||
166 | 2 | if ( $view->settings->get( 'show_only_approved' ) && ! $is_admin_and_can_view ) { |
|
167 | 1 | if ( ! \GravityView_Entry_Approval_Status::is_approved( gform_get_meta( $entry->ID, \GravityView_Entry_Approval::meta_key ) ) ) { |
|
168 | 1 | gravityview()->log->error( 'Entry ID #{entry_id} is not approved for viewing', array( 'entry_id' => $entry->ID ) ); |
|
169 | 1 | return __( 'You are not allowed to view this content.', 'gravityview' ); |
|
170 | } |
||
171 | } |
||
172 | |||
173 | 2 | $error = \GVCommon::check_entry_display( $entry->as_entry() ); |
|
174 | |||
175 | 2 | if( is_wp_error( $error ) ) { |
|
176 | 1 | gravityview()->log->error( 'Entry ID #{entry_id} is not approved for viewing: {message}', array( 'entry_id' => $entry->ID, 'message' => $error->get_error_message() ) ); |
|
177 | 1 | return __( 'You are not allowed to view this content.', 'gravityview' ); |
|
178 | } |
||
179 | |||
180 | 2 | $renderer = new \GV\Entry_Renderer(); |
|
181 | 2 | return $renderer->render( $entry, $view, $request ); |
|
182 | |||
183 | /** |
||
184 | * Just this view. |
||
185 | */ |
||
186 | } else { |
||
187 | 4 | if ( $is_reembedded ) { |
|
188 | |||
189 | // Mock the request with the actual View, not the global one |
||
190 | $mock_request = new \GV\Mock_Request(); |
||
191 | $mock_request->returns['is_view'] = $view; |
||
192 | $mock_request->returns['is_entry'] = $request->is_entry(); |
||
193 | $mock_request->returns['is_edit_entry'] = $request->is_edit_entry(); |
||
194 | $mock_request->returns['is_search'] = $request->is_search(); |
||
195 | |||
196 | $request = $mock_request; |
||
197 | } |
||
198 | |||
199 | 4 | $renderer = new \GV\View_Renderer(); |
|
200 | 4 | return $renderer->render( $view, $request ); |
|
201 | } |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * Validate attributes passed to the [gravityview] shortcode. Supports {get} Merge Tags values. |
||
206 | * |
||
207 | * Attributes passed to the shortcode are compared to registered attributes {@see \GV\View_Settings::defaults} |
||
208 | * Only attributes that are defined will be allowed through. |
||
209 | * |
||
210 | * Then, {get} merge tags are replaced with their $_GET values, if passed |
||
211 | * |
||
212 | * Then, attributes are sanitized based on the type of setting (number, checkbox, select, radio, text) |
||
213 | * |
||
214 | * @see \GV\View_Settings::defaults() Only attributes defined in default() are valid to be passed via the shortcode |
||
215 | * |
||
216 | * @param array $passed_atts Attribute pairs defined to render the View |
||
217 | * |
||
218 | * @return array Valid and sanitized attribute pairs |
||
219 | */ |
||
220 | 5 | private function parse_and_sanitize_atts( $passed_atts ) { |
|
279 | |||
280 | /** |
||
281 | * Output view details. |
||
282 | * |
||
283 | * @param \GV\View $view The View. |
||
284 | * @param \GV\Entry_Collection $entries The calculated entries. |
||
285 | * @param array $atts The shortcode attributes (with defaults). |
||
286 | * |
||
287 | * @return string The output. |
||
288 | */ |
||
289 | 1 | private function detail( $view, $entries, $atts ) { |
|
321 | } |
||
322 |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.