Control   B
last analyzed

Complexity

Total Complexity 45

Size/Duplication

Total Lines 274
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 96.63%

Importance

Changes 0
Metric Value
wmc 45
lcom 1
cbo 5
dl 0
loc 274
ccs 86
cts 89
cp 0.9663
rs 8.8
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 5 1
F render() 0 146 21
A _hasPermission() 0 4 1
F _showAction() 0 35 22

How to fix   Complexity   

Complex Class

Complex classes like Control 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 Control, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace Redaxscript\Admin\View\Helper;
3
4
use Redaxscript\Admin;
5
use Redaxscript\Html;
6
use Redaxscript\Module;
7
use function array_replace_recursive;
8
use function in_array;
9
use function ucfirst;
10
11
/**
12
 * helper class to create the admin control
13
 *
14
 * @since 4.0.0
15
 *
16
 * @package Redaxscript
17
 * @category View
18
 * @author Henry Ruhs
19
 */
20
21
class Control extends Admin\View\ViewAbstract
22
{
23
	/**
24
	 * options of the panel
25
	 *
26
	 * @var array
27
	 */
28
29
	protected $_optionArray =
30
	[
31
		'className' =>
32
		[
33
			'list' => 'rs-admin-list-control',
34
			'item' =>
35
			[
36
				'control' => 'rs-admin-item-control',
37
				'disable' => 'rs-admin-item-disable',
38
				'enable' => 'rs-admin-item-enable',
39
				'future-posting' => 'rs-admin-item-future-posting',
40
				'unpublish' => 'rs-admin-item-unpublish',
41
				'publish' => 'rs-admin-item-publish',
42
				'edit' => 'rs-admin-item-edit',
43
				'delete' => 'rs-admin-item-delete',
44
				'install' => 'rs-admin-item-install',
45
				'uninstall' => 'rs-admin-item-uninstall'
46
			],
47
			'link' =>
48
			[
49
				'delete' => 'rs-admin-js-delete',
50
				'uninstall' => 'rs-admin-js-uninstall'
51
			]
52
		]
53
	];
54
55
	/**
56
	 * init the class
57
	 *
58
	 * @since 4.0.0
59
	 *
60
	 * @param array $optionArray options of the panel
61
	 *
62
	 * @return self
63
	 */
64
65
	public function init(array $optionArray = []) : self
66
	{
67
		$this->_optionArray = array_replace_recursive($this->_optionArray, $optionArray);
68
		return $this;
69
	}
70
71
	/**
72
	 * render the view
73
	 *
74
	 * @since 4.0.0
75
	 *
76
	 * @param string $table name of the table
77
	 * @param int $id identifier of the item
78
	 * @param string $alias alias of the item
79
	 * @param int $status status of the item
80
	 *
81 12
	 * @return string|null
82
	 */
83 12
84 12
	public function render(string $table = null, int $id = null, string $alias = null, int $status = null) : ?string
85 12
	{
86 12
		$output = Module\Hook::trigger('adminControlStart');
87
		$outputItem = null;
88
		$parameterRoute = $this->_registry->get('parameterRoute');
89
		$token = $this->_registry->get('token');
90 12
91
		/* html element */
92 12
93 12
		$element = new Html\Element();
94
		$listElement = $element
95 12
			->copy()
96
			->init('ul',
97
			[
98 12
				'class' => $this->_optionArray['className']['list']
99 12
			]);
100
		$itemElement = $element
101 12
			->copy()
102
			->init('li',
103
			[
104 12
				'class' => $this->_optionArray['className']['item']['control']
105 12
			]);
106
		$linkElement = $element
107 12
			->copy()
108 12
			->init('a');
109
		$textElement = $element
110
			->copy()
111
			->init('span');
112 12
113
		/* collect enable */
114 2
115
		if ($this->_hasPermission($table, 'edit') && $this->_showAction($table, 'enable', $id))
116 2
		{
117 2
			$enableAction = $status ? 'disable' : 'enable';
118 2
			$outputItem .= $itemElement
119
				->copy()
120 2
				->addClass($enableAction === 'disable' ? $this->_optionArray['className']['item']['disable'] : $this->_optionArray['className']['item']['enable'])
121 2
				->html(
122 2
					$linkElement
123
						->copy()
124
						->attr('href', $parameterRoute . 'admin/' . $enableAction . '/' . $table . '/' . $id . '/' . $token)
125
						->text($enableAction === 'disable' ? $this->_language->get('disable') : $this->_language->get('enable'))
0 ignored issues
show
Bug introduced by Henry Ruhs
It seems like $enableAction === 'disab...language->get('enable') can also be of type array; however, Redaxscript\Html\Element::text() does only seem to accept string|integer|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
126
				);
127
		}
128 12
129
		/* collect publish */
130 3
131
		if ($this->_hasPermission($table, 'edit') && $this->_showAction($table, 'publish', $id))
132
		{
133 1
			if ($status === 2)
134 1
			{
135 1
				$outputItem .= $itemElement
136
					->copy()
137 1
					->addClass($this->_optionArray['className']['item']['future-posting'])
138 1
					->html(
139
						$textElement
140
							->copy()
141
							->text($this->_language->get('future_posting'))
0 ignored issues
show
Bug introduced by Henry Ruhs
It seems like $this->_language->get('future_posting') targeting Redaxscript\Language::get() can also be of type array; however, Redaxscript\Html\Element::text() does only seem to accept string|integer|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
142
					);
143 2
			}
144
			else
145 2
			{
146 2
				$publishAction = $status ? 'unpublish' : 'publish';
147 2
				$outputItem .= $itemElement
148
					->copy()
149 2
					->addClass($publishAction === 'unpublish' ? $this->_optionArray['className']['item']['unpublish'] : $this->_optionArray['className']['item']['publish'])
150 2
					->html(
151 2
						$linkElement
152
							->copy()
153
							->attr('href', $parameterRoute . 'admin/' . $publishAction . '/' . $table . '/' . $id . '/' . $token)
154
							->text($publishAction === 'unpublish' ? $this->_language->get('unpublish') : $this->_language->get('publish'))
0 ignored issues
show
Bug introduced by Henry Ruhs
It seems like $publishAction === 'unpu...anguage->get('publish') can also be of type array; however, Redaxscript\Html\Element::text() does only seem to accept string|integer|null, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
155
					);
156
			}
157
		}
158 12
159
		/* collect install */
160
161 1
		if ($this->_hasPermission($table, 'install') && $this->_showAction($table, 'install', $id))
162 1
		{
163 1
			$outputItem .= $itemElement
164
				->copy()
165 1
				->addClass($this->_optionArray['className']['item']['install'])
166 1
				->html(
167 1
					$linkElement
168
						->copy()
169
						->attr('href', $parameterRoute . 'admin/install/' . $table . '/' . $alias . '/' . $token)
170
						->text($this->_language->get('install'))
0 ignored issues
show
Bug introduced by Henry Ruhs
It seems like $this->_language->get('install') targeting Redaxscript\Language::get() can also be of type array; however, Redaxscript\Html\Element::text() does only seem to accept string|integer|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
171
				);
172
		}
173 12
174
		/* collect edit */
175
176 6
		if ($this->_hasPermission($table, 'edit') && $this->_showAction($table, 'edit', $id))
177 6
		{
178 6
			$outputItem .= $itemElement
179
				->copy()
180 6
				->addClass($this->_optionArray['className']['item']['edit'])
181 6
				->html(
182 6
					$linkElement
183
						->copy()
184
						->attr('href', $parameterRoute . 'admin/edit/' . $table . '/' . $id)
185
						->text($this->_language->get('edit'))
0 ignored issues
show
Bug introduced by Henry Ruhs
It seems like $this->_language->get('edit') targeting Redaxscript\Language::get() can also be of type array; however, Redaxscript\Html\Element::text() does only seem to accept string|integer|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
186
				);
187
		}
188 12
189
		/* collect delete */
190
191 3
		if ($this->_hasPermission($table, 'delete') && $this->_showAction($table, 'delete', $id))
192 3
		{
193 3
			$outputItem .= $itemElement
194
				->copy()
195 3
				->addClass($this->_optionArray['className']['item']['delete'])
196 3
				->html(
197 3
					$linkElement
198 3
						->copy()
199
						->addClass($this->_optionArray['className']['link']['delete'])
200
						->attr('href', $parameterRoute . 'admin/delete/' . $table . '/' . $id . '/' . $token)
201
						->text($this->_language->get('delete'))
0 ignored issues
show
Bug introduced by Henry Ruhs
It seems like $this->_language->get('delete') targeting Redaxscript\Language::get() can also be of type array; however, Redaxscript\Html\Element::text() does only seem to accept string|integer|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
202
				);
203
		}
204 12
205
		/* collect uninstall */
206
207 1
		if ($this->_hasPermission($table, 'uninstall') && $this->_showAction($table, 'uninstall', $id))
208 1
		{
209 1
			$outputItem .= $itemElement
210
				->copy()
211 1
				->addClass($this->_optionArray['className']['item']['uninstall'])
212 1
				->html(
213 1
					$linkElement
214 1
						->copy()
215
						->addClass($this->_optionArray['className']['link']['uninstall'])
216
						->attr('href', $parameterRoute . 'admin/uninstall/' . $table . '/' . $alias . '/' . $token)
217
						->text($this->_language->get('uninstall'))
0 ignored issues
show
Bug introduced by redaxmedia
It seems like $this->_language->get('uninstall') targeting Redaxscript\Language::get() can also be of type array; however, Redaxscript\Html\Element::text() does only seem to accept string|integer|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
218
				);
219
		}
220 12
221
		/* collect output */
222 9
223
		if ($outputItem)
0 ignored issues
show
Bug Best Practice introduced by redaxmedia
The expression $outputItem of type string|null is loosely compared to true; this is ambiguous if the string can be empty. 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 string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
224 12
		{
225 12
			$output .= $listElement->html($outputItem);
226
		}
227
		$output .= Module\Hook::trigger('adminControlEnd');
228
		return $output;
229
	}
230
231
	/**
232
	 * has the permission
233
	 *
234
	 * @since 4.0.0
235
	 *
236
	 * @param string $table name of the table
237
	 * @param string $type
238
	 *
239 12
	 * @return bool
240
	 */
241 12
242
	protected function _hasPermission(string $table = null, string $type = null) : bool
243
	{
244
		return (bool)$this->_registry->get($table . ucfirst($type));
245
	}
246
247
	/**
248
	 * show the action
249
	 *
250
	 * @since 4.0.0
251
	 *
252
	 * @param string $table name of the table
253
	 * @param string $type
254
	 * @param int $id
255
	 *
256 9
	 * @return bool
257
	 */
258
259
	protected function _showAction(string $table = null, string $type = null, int $id = null) : bool
260 9
	{
261
		$enableArray =
262
		[
263
			'groups',
264
			'users',
265
			'modules'
266 9
		];
267
		$publishArray =
268
		[
269
			'categories',
270
			'articles',
271
			'extras',
272
			'comments'
273 9
		];
274
		$deleteArray =
275
		[
276
			'categories',
277
			'articles',
278
			'extras',
279
			'comments',
280 9
			'groups',
281
			'users'
282 1
		];
283
		if ($id === 1 && ($type === 'enable' || $type === 'delete') && ($table === 'users' || $table === 'groups'))
284 9
		{
285 9
			return false;
286 9
		}
287 8
		return $type === 'enable' && in_array($table, $enableArray) && $id ||
0 ignored issues
show
Bug Best Practice introduced by redaxmedia
The expression $id of type null|integer 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...
288 7
			$type === 'publish' && in_array($table, $publishArray) && $id ||
0 ignored issues
show
Bug Best Practice introduced by redaxmedia
The expression $id of type null|integer 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...
289 9
			$type === 'delete' && in_array($table, $deleteArray) && $id ||
0 ignored issues
show
Bug Best Practice introduced by redaxmedia
The expression $id of type null|integer 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...
290
			$type === 'install' && $table === 'modules' && !$id ||
0 ignored issues
show
Bug Best Practice introduced by redaxmedia
The expression $id of type null|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...
291
			$type === 'uninstall' && $table === 'modules' && $id ||
0 ignored issues
show
Bug Best Practice introduced by redaxmedia
The expression $id of type null|integer 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...
292
			$type === 'edit' && $id;
0 ignored issues
show
Bug Best Practice introduced by redaxmedia
The expression $id of type null|integer 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...
293
	}
294
}
295