Passed
Push — master ( 0de278...836c6f )
by Paul
04:15
created

ListTableController   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 277
Duplicated Lines 0 %

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 0
loc 277
ccs 0
cts 119
cp 0
rs 8.3999
c 0
b 0
f 0
wmc 46

18 Methods

Rating   Name   Duplication   Size   Complexity  
A filterDefaultHiddenColumns() 0 6 2
B filterColumnsForPostType() 0 11 5
A filterSortableColumns() 0 9 3
A renderBulkEditFields() 0 4 3
A filterStatusText() 0 17 4
A approve() 0 9 1
A filterBulkUpdateMessages() 0 10 1
A filterRowActions() 0 21 4
A setQueryForColumn() 0 7 2
A saveBulkEditFields() 0 5 4
A renderColumnValues() 0 3 1
A getTranslation() 0 13 2
A setOrderby() 0 8 2
A setMetaQuery() 0 10 3
A canModifyTranslation() 0 5 3
A renderColumnFilters() 0 3 1
A hasPermission() 0 7 4
A unapprove() 0 9 1

How to fix   Complexity   

Complex Class

Complex classes like ListTableController 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.

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 ListTableController, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace GeminiLabs\SiteReviews\Controllers;
4
5
use GeminiLabs\SiteReviews\Application;
6
use GeminiLabs\SiteReviews\Database;
7
use GeminiLabs\SiteReviews\Controllers\Controller;
8
use GeminiLabs\SiteReviews\Helper;
9
use GeminiLabs\SiteReviews\Modules\Html;
10
use GeminiLabs\SiteReviews\Modules\Html\Builder;
11
use GeminiLabs\SiteReviews\Modules\ListTable\Columns;
12
use WP_Post;
13
use WP_Screen;
14
use WP_Query;
15
16
class ListTableController extends Controller
17
{
18
	/**
19
	 * @return void
20
	 * @action admin_action_approve
21
	 */
22
	public function approve()
23
	{
24
		check_admin_referer( 'approve-review_'.( $postId = $this->getPostId() ));
25
		wp_update_post([
26
			'ID' => $postId,
27
			'post_status' => 'publish',
28
		]);
29
		wp_safe_redirect( wp_get_referer() );
30
		exit;
1 ignored issue
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
31
	}
32
33
	/**
34
	 * @return array
35
	 * @filter bulk_post_updated_messages
36
	 */
37
	public function filterBulkUpdateMessages( array $messages, array $counts )
38
	{
39
		$messages[Application::POST_TYPE] = [
40
			'updated' => _n( '%s review updated.', '%s reviews updated.', $counts['updated'], 'site-reviews' ),
41
			'locked' => _n( '%s review not updated, somebody is editing it.', '%s reviews not updated, somebody is editing them.', $counts['locked'], 'site-reviews' ),
42
			'deleted' => _n( '%s review permanently deleted.', '%s reviews permanently deleted.', $counts['deleted'], 'site-reviews' ),
43
			'trashed' => _n( '%s review moved to the Trash.', '%s reviews moved to the Trash.', $counts['trashed'], 'site-reviews' ),
44
			'untrashed' => _n( '%s review restored from the Trash.', '%s reviews restored from the Trash.', $counts['untrashed'], 'site-reviews' ),
45
		];
46
		return $messages;
47
	}
48
49
	/**
50
	 * @return array
51
	 * @filter manage_.Application::POST_TYPE._posts_columns
52
	 */
53
	public function filterColumnsForPostType( array $columns )
54
	{
55
		$postTypeColumns = glsr()->postTypeColumns[Application::POST_TYPE];
56
		foreach( $postTypeColumns as $key => &$value ) {
57
			if( !array_key_exists( $key, $columns ) || !empty( $value ))continue;
58
			$value = $columns[$key];
59
		}
60
		if( count( glsr( Database::class )->getReviewsMeta( 'type' )) < 2 ) {
61
			unset( $postTypeColumns['review_type'] );
62
		}
63
		return array_filter( $postTypeColumns, 'strlen' );
64
	}
65
66
	/**
67
	 * @return array
68
	 * @filter default_hidden_columns
69
	 */
70
	public function filterDefaultHiddenColumns( array $hidden, WP_Screen $screen )
71
	{
72
		if( $screen->id == 'edit-'.Application::POST_TYPE ) {
73
			$hidden = ['reviewer'];
74
		}
75
		return $hidden;
76
	}
77
78
	/**
79
	 * @return array
80
	 * @filter post_row_actions
81
	 */
82
	public function filterRowActions( array $actions, WP_Post $post )
83
	{
84
		if( $post->post_type != Application::POST_TYPE || $post->post_status == 'trash' ) {
85
			return $actions;
86
		}
87
		unset( $actions['inline hide-if-no-js'] ); //Remove Quick-edit
88
		$rowActions = [
89
			'approve' => esc_attr__( 'Approve', 'site-reviews' ),
90
			'unapprove' => esc_attr__( 'Unapprove', 'site-reviews' ),
91
		];
92
		foreach( $rowActions as $key => $text ) {
93
			$actions[$key] = glsr( Builder::class )->a( $text, [
94
				'aria-label' => sprintf( esc_attr_x( '%s this review', 'Approve the review', 'site-reviews' ), text ),
0 ignored issues
show
Bug introduced by
The constant GeminiLabs\SiteReviews\Controllers\text was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
95
				'class' => 'change-'.Application::POST_TYPE.'-status',
96
				'href' => wp_nonce_url(
97
					admin_url( 'post.php?post='.$post->ID.'&action='.$key ),
98
					$key.'-review_'.$post->ID
99
				),
100
			]);
101
		}
102
		return $actions;
103
	}
104
105
	/**
106
	 * @return array
107
	 * @filter manage_edit-.Application::POST_TYPE._sortable_columns
108
	 */
109
	public function filterSortableColumns( array $columns )
110
	{
111
		$postTypeColumns = glsr()->postTypeColumns[Application::POST_TYPE];
112
		unset( $postTypeColumns['cb'] );
113
		foreach( $postTypeColumns as $key => $value ) {
114
			if( glsr( Helper::class )->startsWith( 'taxonomy', $key ))continue;
115
			$columns[$key] = $key;
116
		}
117
		return $columns;
118
	}
119
120
	/**
121
	 * Customize the post_type status text
122
	 * @param string $translation
123
	 * @param string $single
124
	 * @param string $plural
125
	 * @param int $number
126
	 * @param string $domain
127
	 * @return string
128
	 * @filter ngettext
129
	 */
130
	public function filterStatusText( $translation, $single, $plural, $number, $domain )
131
	{
132
		if( $this->canModifyTranslation( $domain )) {
133
			$strings = [
134
				'Published' => __( 'Approved', 'site-reviews' ),
135
				'Pending' => __( 'Unapproved', 'site-reviews' ),
136
			];
137
			foreach( $strings as $search => $replace ) {
138
				if( strpos( $single, $search ) === false )continue;
139
				$translation = $this->getTranslation([
140
					'number' => $number,
141
					'plural' => str_replace( $search, $replace, $plural ),
142
					'single' => str_replace( $search, $replace, $single ),
143
				]);
144
			}
145
		}
146
		return $translation;
147
	}
148
149
	/**
150
	 * @param string $columnName
151
	 * @param string $postType
152
	 * @return void
153
	 * @action bulk_edit_custom_box
154
	 */
155
	public function renderBulkEditFields( $columnName, $postType )
156
	{
157
		if( $columnName == 'assigned_to' && $postType == Application::POST_TYPE ) {
158
			$this->render( 'edit/bulk-edit-assigned-to' );
0 ignored issues
show
Bug introduced by
The method render() does not exist on GeminiLabs\SiteReviews\C...ers\ListTableController. Did you maybe mean renderColumnFilters()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

158
			$this->/** @scrutinizer ignore-call */ 
159
          render( 'edit/bulk-edit-assigned-to' );

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
159
		};
160
	}
161
162
	/**
163
	 * @param string $postType
164
	 * @return void
165
	 * @action restrict_manage_posts
166
	 */
167
	public function renderColumnFilters( $postType )
168
	{
169
		glsr( Columns::class )->renderFilters( $postType );
170
	}
171
172
	/**
173
	 * @param string $column
174
	 * @return void
175
	 * @action manage_posts_custom_column
176
	 */
177
	public function renderColumnValues( $column, $postId )
178
	{
179
		glsr( Columns::class )->renderValues( $column, $postId );
180
	}
181
182
	/**
183
	 * @param int $postId
184
	 * @return void
185
	 * @action save_post_.Application::POST_TYPE
186
	 */
187
	public function saveBulkEditFields( $postId )
188
	{
189
		if( !current_user_can( 'edit_posts' ))return;
190
		if( $assignedTo = filter_input( INPUT_GET, 'assigned_to' ) && get_post( $assignedTo )) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $assignedTo seems to be never defined.
Loading history...
Comprehensibility introduced by
Consider adding parentheses for clarity. Current Interpretation: $assignedTo = (filter_in... get_post($assignedTo)), Probably Intended Meaning: ($assignedTo = filter_in...& get_post($assignedTo)
Loading history...
191
			update_post_meta( $postId, 'assigned_to', $assignedTo );
192
		}
193
	}
194
195
	/**
196
	 * @return void
197
	 * @action pre_get_posts
198
	 */
199
	public function setQueryForColumn( WP_Query $query )
200
	{
201
		if( !$this->hasPermission( $query ))return;
202
		$this->setMetaQuery( $query, [
203
			'rating', 'review_type',
204
		]);
205
		$this->setOrderby( $query );
206
	}
207
208
	/**
209
	 * @return void
210
	 * @action admin_action_unapprove
211
	 */
212
	public function unapprove()
213
	{
214
		check_admin_referer( 'unapprove-review_'.( $postId = $this->getPostId() ));
215
		wp_update_post([
216
			'ID' => $postId,
217
			'post_status' => 'pending',
218
		]);
219
		wp_safe_redirect( wp_get_referer() );
220
		exit;
1 ignored issue
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
221
	}
222
223
	/**
224
	 * Check if the translation string can be modified
225
	 * @param string $domain
226
	 * @return bool
227
	 */
228
	protected function canModifyTranslation( $domain = 'default' )
229
	{
230
		return $domain == 'default'
231
			&& glsr_current_screen()->base == 'edit'
232
			&& glsr_current_screen()->post_type == Application::POST_TYPE;
233
	}
234
235
	/**
236
	 * Get the modified translation string
237
	 * @return string
238
	 */
239
	protected function getTranslation( array $args )
240
	{
241
		$defaults = [
242
			'number' => 0,
243
			'plural' => '',
244
			'single' => '',
245
			'text' => '',
246
		];
247
		$args = (object) wp_parse_args( $args, $defaults );
248
		$translations = get_translations_for_domain( Application::ID );
249
		return $args->text
250
			? $translations->translate( $args->text )
251
			: $translations->translate_plural( $args->single, $args->plural, $args->number );
252
	}
253
254
	/**
255
	 * @return bool
256
	 */
257
	protected function hasPermission( WP_Query $query )
258
	{
259
		global $pagenow;
1 ignored issue
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
260
		return is_admin()
261
			&& $query->is_main_query()
262
			&& $query->get( 'post_type' ) == Application::POST_TYPE
263
			&& $pagenow == 'edit.php';
264
	}
265
266
	/**
267
	 * @return void
268
	 */
269
	protected function setMetaQuery( WP_Query $query, array $metaKeys )
270
	{
271
		foreach( $metaKeys as $key ) {
272
			if( !( $value = filter_input( INPUT_GET, $key )))continue;
273
			$metaQuery = (array)$query->get( 'meta_query' );
274
			$metaQuery[] = [
275
				'key' => $key,
276
				'value' => $value,
277
			];
278
			$query->set( 'meta_query', $metaQuery );
279
		}
280
	}
281
282
	/**
283
	 * @return void
284
	 */
285
	protected function setOrderby( WP_Query $query )
286
	{
287
		$orderby = $query->get( 'orderby' );
288
		$columns = glsr()->postTypeColumns[Application::POST_TYPE];
289
		unset( $columns['cb'], $columns['title'], $columns['date'] );
290
		if( in_array( $orderby, array_keys( $columns ))) {
291
			$query->set( 'meta_key', $orderby );
292
			$query->set( 'orderby', 'meta_value' );
293
		}
294
	}
295
}
296