Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
1 | <?php |
||
12 | class Sensei_Analysis_Lesson_List_Table extends WooThemes_Sensei_List_Table { |
||
13 | public $lesson_id; |
||
14 | public $course_id; |
||
15 | public $page_slug = 'sensei_analysis'; |
||
16 | |||
17 | /** |
||
18 | * Constructor |
||
19 | * @since 1.2.0 |
||
20 | */ |
||
21 | public function __construct ( $lesson_id = 0 ) { |
||
22 | $this->lesson_id = intval( $lesson_id ); |
||
23 | $this->course_id = intval( get_post_meta( $this->lesson_id, '_lesson_course', true ) ); |
||
24 | |||
25 | // Load Parent token into constructor |
||
26 | parent::__construct( 'analysis_lesson' ); |
||
27 | |||
28 | // Actions |
||
29 | add_action( 'sensei_before_list_table', array( $this, 'data_table_header' ) ); |
||
30 | add_action( 'sensei_after_list_table', array( $this, 'data_table_footer' ) ); |
||
31 | |||
32 | add_filter( 'sensei_list_table_search_button_text', array( $this, 'search_button' ) ); |
||
33 | } // End __construct() |
||
34 | |||
35 | /** |
||
36 | * Define the columns that are going to be used in the table |
||
37 | * @since 1.7.0 |
||
38 | * @return array $columns, the array of columns to use with the table |
||
39 | */ |
||
40 | View Code Duplication | function get_columns() { |
|
41 | $columns = array( |
||
42 | 'title' => __( 'Learner', 'woothemes-sensei' ), |
||
43 | 'started' => __( 'Date Started', 'woothemes-sensei' ), |
||
44 | 'completed' => __( 'Date Completed', 'woothemes-sensei' ), |
||
45 | 'status' => __( 'Status', 'woothemes-sensei' ), |
||
46 | 'grade' => __( 'Grade', 'woothemes-sensei' ), |
||
47 | ); |
||
48 | $columns = apply_filters( 'sensei_analysis_lesson_columns', $columns, $this ); |
||
49 | return $columns; |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * get_columns Define the columns that are going to be used in the table |
||
54 | * @since 1.7.0 |
||
55 | * @return array $columns, the array of columns to use with the table |
||
56 | */ |
||
57 | View Code Duplication | function get_sortable_columns() { |
|
58 | $columns = array( |
||
59 | 'title' => array( 'title', false ), |
||
60 | 'started' => array( 'started', false ), |
||
61 | 'completed' => array( 'completed', false ), |
||
62 | 'status' => array( 'status', false ), |
||
63 | 'grade' => array( 'grade', false ), |
||
64 | ); |
||
65 | $columns = apply_filters( 'sensei_analysis_lesson_columns_sortable', $columns, $this ); |
||
66 | return $columns; |
||
67 | } |
||
68 | |||
69 | /** |
||
70 | * Prepare the table with different parameters, pagination, columns and table elements |
||
71 | * @since 1.7.0 |
||
72 | * @return void |
||
73 | */ |
||
74 | View Code Duplication | public function prepare_items() { |
|
75 | global $per_page; |
||
76 | |||
77 | // Handle orderby (needs work) |
||
78 | $orderby = ''; |
||
79 | if ( !empty( $_GET['orderby'] ) ) { |
||
80 | if ( array_key_exists( esc_html( $_GET['orderby'] ), $this->get_sortable_columns() ) ) { |
||
81 | $orderby = esc_html( $_GET['orderby'] ); |
||
82 | } // End If Statement |
||
83 | } |
||
84 | |||
85 | // Handle order |
||
86 | $order = 'ASC'; |
||
87 | if ( !empty( $_GET['order'] ) ) { |
||
88 | $order = ( 'ASC' == strtoupper($_GET['order']) ) ? 'ASC' : 'DESC'; |
||
89 | } |
||
90 | |||
91 | // Handle search, need 4.1 version of WP to be able to restrict statuses to known post_ids |
||
92 | $search = false; |
||
93 | if ( !empty( $_GET['s'] ) ) { |
||
94 | $search = esc_html( $_GET['s'] ); |
||
95 | } // End If Statement |
||
96 | $this->search = $search; |
||
97 | |||
98 | $per_page = $this->get_items_per_page( 'sensei_comments_per_page' ); |
||
99 | $per_page = apply_filters( 'sensei_comments_per_page', $per_page, 'sensei_comments' ); |
||
100 | |||
101 | $paged = $this->get_pagenum(); |
||
102 | $offset = 0; |
||
103 | if ( !empty($paged) ) { |
||
104 | $offset = $per_page * ( $paged - 1 ); |
||
105 | } // End If Statement |
||
106 | |||
107 | $args = array( |
||
108 | 'number' => $per_page, |
||
109 | 'offset' => $offset, |
||
110 | 'orderby' => $orderby, |
||
111 | 'order' => $order, |
||
112 | ); |
||
113 | if ( $this->search ) { |
||
114 | $args['search'] = $this->search; |
||
115 | } // End If Statement |
||
116 | |||
117 | $this->items = $this->get_lesson_statuses( $args ); |
||
118 | |||
119 | $total_items = $this->total_items; |
||
120 | $total_pages = ceil( $total_items / $per_page ); |
||
121 | $this->set_pagination_args( array( |
||
122 | 'total_items' => $total_items, |
||
123 | 'total_pages' => $total_pages, |
||
124 | 'per_page' => $per_page |
||
125 | ) ); |
||
126 | } |
||
127 | |||
128 | /** |
||
129 | * Generate a csv report with different parameters, pagination, columns and table elements |
||
130 | * @since 1.7.0 |
||
131 | * @return data |
||
132 | */ |
||
133 | View Code Duplication | public function generate_report( $report ) { |
|
134 | |||
135 | $data = array(); |
||
136 | |||
137 | $this->csv_output = true; |
||
138 | |||
139 | // Handle orderby |
||
140 | $orderby = ''; |
||
141 | if ( !empty( $_GET['orderby'] ) ) { |
||
142 | if ( array_key_exists( esc_html( $_GET['orderby'] ), $this->get_sortable_columns() ) ) { |
||
143 | $orderby = esc_html( $_GET['orderby'] ); |
||
144 | } // End If Statement |
||
145 | } |
||
146 | |||
147 | // Handle order |
||
148 | $order = 'ASC'; |
||
149 | if ( !empty( $_GET['order'] ) ) { |
||
150 | $order = ( 'ASC' == strtoupper($_GET['order']) ) ? 'ASC' : 'DESC'; |
||
151 | } |
||
152 | |||
153 | // Handle search |
||
154 | $search = false; |
||
155 | if ( !empty( $_GET['s'] ) ) { |
||
156 | $search = esc_html( $_GET['s'] ); |
||
157 | } // End If Statement |
||
158 | $this->search = $search; |
||
159 | |||
160 | $args = array( |
||
161 | 'orderby' => $orderby, |
||
162 | 'order' => $order, |
||
163 | ); |
||
164 | if ( $this->search ) { |
||
165 | $args['search'] = $this->search; |
||
166 | } // End If Statement |
||
167 | |||
168 | // Start the csv with the column headings |
||
169 | $column_headers = array(); |
||
170 | $columns = $this->get_columns(); |
||
171 | foreach( $columns AS $key => $title ) { |
||
172 | $column_headers[] = $title; |
||
173 | } |
||
174 | $data[] = $column_headers; |
||
175 | |||
176 | $this->items = $this->get_lesson_statuses( $args ); |
||
177 | |||
178 | // Process each row |
||
179 | foreach( $this->items AS $item) { |
||
180 | $data[] = $this->get_row_data( $item ); |
||
181 | } |
||
182 | |||
183 | return $data; |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Generates the overall array for a single item in the display |
||
188 | * |
||
189 | * @since 1.7.0 |
||
190 | * @param object $item The current item |
||
191 | */ |
||
192 | protected function get_row_data( $item ) { |
||
193 | |||
194 | $user_start_date = get_comment_meta( $item->comment_ID, 'start', true ); |
||
195 | $user_end_date = $item->comment_date; |
||
196 | $status_class = $grade = ''; |
||
197 | |||
198 | View Code Duplication | if( 'complete' == $item->comment_approved ) { |
|
199 | $status = __( 'Completed', 'woothemes-sensei' ); |
||
200 | $status_class = 'graded'; |
||
201 | |||
202 | $grade = __( 'No Grade', 'woothemes-sensei' ); |
||
203 | } |
||
204 | elseif( 'graded' == $item->comment_approved ) { |
||
205 | $status = __( 'Graded', 'woothemes-sensei' ) ; |
||
206 | $status_class = 'graded'; |
||
207 | |||
208 | $grade = get_comment_meta( $item->comment_ID, 'grade', true); |
||
209 | } |
||
210 | elseif( 'passed' == $item->comment_approved ) { |
||
211 | $status = __( 'Passed', 'woothemes-sensei' ); |
||
212 | $status_class = 'graded'; |
||
213 | |||
214 | $grade = get_comment_meta( $item->comment_ID, 'grade', true); |
||
215 | } |
||
216 | elseif( 'failed' == $item->comment_approved ) { |
||
217 | $status = __( 'Failed', 'woothemes-sensei' ); |
||
218 | $status_class = 'failed'; |
||
219 | |||
220 | $grade = get_comment_meta( $item->comment_ID, 'grade', true); |
||
221 | } |
||
222 | elseif( 'ungraded' == $item->comment_approved ) { |
||
223 | $status = __( 'Ungraded', 'woothemes-sensei' ); |
||
224 | $status_class = 'ungraded'; |
||
225 | |||
226 | } |
||
227 | else { |
||
228 | $status = __( 'In Progress', 'woothemes-sensei' ); |
||
229 | $user_end_date = ''; |
||
230 | } |
||
231 | |||
232 | // Output users data |
||
233 | $user_name = Sensei_Learner::get_full_name( $item->user_id ); |
||
234 | |||
235 | View Code Duplication | if ( !$this->csv_output ) { |
|
236 | $url = add_query_arg( array( 'page' => $this->page_slug, 'user_id' => $item->user_id, 'course_id' => $this->course_id ), admin_url( 'admin.php' ) ); |
||
237 | |||
238 | $user_name = '<strong><a class="row-title" href="' . esc_url( $url ) . '">' . $user_name . '</a></strong>'; |
||
239 | $status = sprintf( '<span class="%s">%s</span>', $item->comment_approved, $status ); |
||
240 | if ( is_numeric($grade) ) { |
||
241 | $grade .= '%'; |
||
242 | } |
||
243 | } // End If Statement |
||
244 | $column_data = apply_filters( 'sensei_analysis_lesson_column_data', array( 'title' => $user_name, |
||
245 | 'started' => $user_start_date, |
||
246 | 'completed' => $user_end_date, |
||
247 | 'status' => $status, |
||
248 | 'grade' => $grade, |
||
249 | ), $item, $this ); |
||
250 | |||
251 | return $column_data; |
||
252 | } |
||
253 | |||
254 | /** |
||
255 | * Return array of lesson statuses |
||
256 | * @since 1.7.0 |
||
257 | * @return array statuses |
||
258 | */ |
||
259 | View Code Duplication | private function get_lesson_statuses( $args ) { |
|
260 | |||
261 | $activity_args = array( |
||
262 | 'post_id' => $this->lesson_id, |
||
263 | 'type' => 'sensei_lesson_status', |
||
264 | 'number' => $args['number'], |
||
265 | 'offset' => $args['offset'], |
||
266 | 'orderby' => $args['orderby'], |
||
267 | 'order' => $args['order'], |
||
268 | 'status' => 'any', |
||
269 | ); |
||
270 | |||
271 | // Searching users on statuses requires sub-selecting the statuses by user_ids |
||
272 | if ( $this->search ) { |
||
273 | $user_args = array( |
||
274 | 'search' => '*' . $this->search . '*', |
||
275 | 'fields' => 'ID', |
||
276 | ); |
||
277 | // Filter for extending |
||
278 | $user_args = apply_filters( 'sensei_analysis_lesson_search_users', $user_args ); |
||
279 | if ( !empty( $user_args ) ) { |
||
280 | $learners_search = new WP_User_Query( $user_args ); |
||
281 | // Store for reuse on counts |
||
282 | $activity_args['user_id'] = (array) $learners_search->get_results(); |
||
283 | } |
||
284 | } // End If Statement |
||
285 | |||
286 | $activity_args = apply_filters( 'sensei_analysis_lesson_filter_statuses', $activity_args ); |
||
287 | |||
288 | // WP_Comment_Query doesn't support SQL_CALC_FOUND_ROWS, so instead do this twice |
||
289 | $this->total_items = Sensei_Utils::sensei_check_for_activity( array_merge( $activity_args, array('count' => true, 'offset' => 0, 'number' => 0) ) ); |
||
290 | |||
291 | // Ensure we change our range to fit (in case a search threw off the pagination) - Should this be added to all views? |
||
292 | if ( $this->total_items < $activity_args['offset'] ) { |
||
293 | $new_paged = floor( $total_statuses / $activity_args['number'] ); |
||
294 | $activity_args['offset'] = $new_paged * $activity_args['number']; |
||
295 | } |
||
296 | $statuses = Sensei_Utils::sensei_check_for_activity( $activity_args, true ); |
||
297 | // Need to always return an array, even with only 1 item |
||
298 | if ( !is_array($statuses) ) { |
||
299 | $statuses = array( $statuses ); |
||
300 | } |
||
301 | return $statuses; |
||
302 | } // End get_lesson_statuses() |
||
303 | |||
304 | /** |
||
305 | * no_items sets output when no items are found |
||
306 | * Overloads the parent method |
||
307 | * @since 1.2.0 |
||
308 | * @return void |
||
309 | */ |
||
310 | public function no_items() { |
||
313 | |||
314 | /** |
||
315 | * data_table_header output for table heading |
||
316 | * @since 1.2.0 |
||
317 | * @return void |
||
318 | */ |
||
319 | public function data_table_header() { |
||
322 | |||
323 | /** |
||
324 | * data_table_footer output for table footer |
||
325 | * @since 1.2.0 |
||
326 | * @return void |
||
327 | */ |
||
328 | View Code Duplication | public function data_table_footer() { |
|
329 | $lesson = get_post( $this->lesson_id ); |
||
334 | |||
335 | /** |
||
336 | * the text for the search button |
||
337 | * @since 1.7.0 |
||
338 | * @return string $text |
||
339 | */ |
||
340 | public function search_button( $text = '' ) { |
||
347 | } // End Class |
||
348 | |||
358 |
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.