InstanceViewer   F
last analyzed

Complexity

Total Complexity 102

Size/Duplication

Total Lines 458
Duplicated Lines 0 %

Importance

Changes 10
Bugs 4 Features 0
Metric Value
eloc 235
c 10
b 4
f 0
dl 0
loc 458
rs 2
wmc 102

44 Methods

Rating   Name   Duplication   Size   Complexity  
A getValues() 0 18 5
A _beforeAddProperty() 0 1 1
A getValue() 0 3 1
A getIdentifier() 0 11 4
A swapFields() 0 5 2
A removeField() 0 5 1
A moveFieldTo() 0 5 2
A _getPropertyValue() 0 3 1
A __construct() 0 10 2
A _getDefaultValue() 0 3 1
A getFieldName() 0 10 3
A visiblePropertiesCount() 0 2 1
A count() 0 2 1
A sortColumnContent() 0 7 3
A addFields() 0 3 1
A insertField() 0 9 2
A addField() 0 9 2
A showableProperty() 0 2 1
B _getValue() 0 26 9
A insertInField() 0 26 5
A _postGetValue() 0 12 4
A getProperty() 0 2 1
A setIdentifierFunction() 0 3 1
A setDefaultValueFunction() 0 3 1
A getVisibleProperties() 0 2 1
B getCaptions() 0 27 10
A addGroupBy() 0 2 1
A getDefaultValueFunction() 0 2 1
A setValueFunction() 0 3 1
A getGroupByFieldsCount() 0 5 2
A getDefaultProperties() 0 10 3
A setCaption() 0 5 2
A setIndex() 0 2 1
A setInstance() 0 19 6
A setGroupByFields() 0 2 1
A setVisibleProperties() 0 3 1
A getSimpleProperties() 0 3 2
A getCaption() 0 10 4
A getGroupByFields() 0 2 1
A setInstanceProperty() 0 20 6
A setCaptions() 0 3 1
A afterCompile() 0 3 1
A setCaptionCallback() 0 3 1
A getProperties() 0 2 1

How to fix   Complexity   

Complex Class

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

1
<?php
2
namespace Ajax\semantic\widgets\base;
3
4
use Ajax\service\JString;
5
use Ajax\service\JArray;
6
use Ajax\service\JReflection;
7
8
class InstanceViewer {
9
10
	protected $widgetIdentifier;
11
12
	protected $instance;
13
14
	protected $reflect;
15
16
	protected $properties;
17
18
	protected $visibleProperties;
19
20
	protected $values;
21
22
	protected $afterCompile;
23
24
	protected $captions;
25
26
	protected $captionCallback;
27
28
	protected $defaultValueFunction;
29
30
	protected $groupByFields;
31
32
	public static $index = 0;
33
34
	public function __construct($identifier, $instance = NULL, $captions = NULL) {
35
		$this->widgetIdentifier = $identifier;
36
		$this->values = [];
37
		$this->afterCompile = [];
38
		if (isset($instance))
39
			$this->setInstance($instance);
40
		$this->setCaptions($captions);
41
		$this->captionCallback = NULL;
42
		$this->defaultValueFunction = function ($name, $value) {
43
			return $value;
44
		};
45
	}
46
47
	public function moveFieldTo($from, $to) {
48
		if (JArray::moveElementTo($this->visibleProperties, $from, $to)) {
49
			return JArray::moveElementTo($this->values, $from, $to);
50
		}
51
		return false;
52
	}
53
54
	public function swapFields($index1, $index2) {
55
		if (JArray::swapElements($this->visibleProperties, $index1, $index2)) {
56
			return JArray::swapElements($this->values, $index1, $index2);
57
		}
58
		return false;
59
	}
60
61
	public function removeField($index) {
62
		\array_splice($this->visibleProperties, $index, 1);
63
		\array_splice($this->values, $index, 1);
64
		\array_splice($this->captions, $index, 1);
65
		return $this;
66
	}
67
68
	public function getValues() {
69
		$values = [];
70
		$index = 0;
71
		$count = $this->count();
72
		$hasGroupby = is_array($this->groupByFields);
73
		if (! $hasGroupby) {
74
			while ($index < $count) {
75
				$values[] = $this->getValue($index ++);
76
			}
77
		} else {
78
			while ($index < $count) {
79
				if (array_search($index, $this->groupByFields) === false) {
80
					$values[] = $this->getValue($index);
81
				}
82
				$index ++;
83
			}
84
		}
85
		return $values;
86
	}
87
88
	public function getIdentifier($index = NULL) {
89
		if (! isset($index))
90
			$index = self::$index;
91
		$value = $index;
92
		if (isset($this->values["identifier"])) {
93
			if (\is_string($this->values["identifier"]))
94
				$value = JReflection::callMethod($this->instance, $this->values["identifier"], []);
95
			else
96
				$value = $this->values["identifier"]($index, $this->instance);
97
		}
98
		return $value;
99
	}
100
101
	public function getValue($index) {
102
		$property = $this->properties[$index];
103
		return $this->_getValue($property, $index);
104
	}
105
106
	protected function _beforeAddProperty($index, &$field) {}
107
108
	protected function _getDefaultValue($name, $value, $index) {
109
		$func = $this->defaultValueFunction;
110
		return $func($name, $value, $index, $this->instance);
111
	}
112
113
	protected function _getPropertyValue(\ReflectionProperty $property) {
114
		$property->setAccessible(true);
115
		return $property->getValue($this->instance);
116
	}
117
118
	protected function _getValue($property, $index) {
119
		$value = null;
120
		$propertyName = $property;
121
		if ($property instanceof \ReflectionProperty) {
122
			$value = $this->_getPropertyValue($property);
123
			$propertyName = $property->getName();
124
		} elseif (\is_callable($property) && \array_search($property, ['system','date']) === false){
125
			try{
126
				$value = $property($this->instance);
127
			}catch(\Error $e){}
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
128
		}
129
		elseif (\is_array($property)) {
130
			$values = \array_map(function ($v) use ($index) {
131
				return $this->_getValue($v, $index);
132
			}, $property);
133
			$value = \implode('', $values);
134
		} elseif (\is_string($property)) {
135
			$value = '';
136
			if (isset($this->instance->{$property})) {
137
				$value = $this->instance->{$property};
138
			} elseif (\method_exists($this->instance, $getter = JReflection::getterName($property))) {
139
				$value = JReflection::callMethod($this->instance, $getter, []);
140
			}
141
		}
142
143
		return $this->_postGetValue($index, $propertyName, $value);
144
	}
145
146
	protected function _postGetValue($index, $propertyName, $value) {
147
		if (isset($this->values[$index])) {
148
			$value = $this->values[$index]($value, $this->instance, $index, self::$index);
149
		} else {
150
			$value = $this->_getDefaultValue($propertyName, $value, $index);
151
		}
152
		if (isset($this->afterCompile[$index])) {
153
			if (\is_callable($this->afterCompile[$index])) {
154
				$this->afterCompile[$index]($value, $this->instance, self::$index);
155
			}
156
		}
157
		return $value;
158
	}
159
160
	public function insertField($index, $field, $key = null) {
161
		if (isset($key)) {
162
			array_splice($this->visibleProperties, $index, 0, [
163
				$key => $field
164
			]);
165
		} else {
166
			array_splice($this->visibleProperties, $index, 0, $field);
167
		}
168
		return $this;
169
	}
170
171
	public function sortColumnContent($index, $array) {
172
		if (isset($this->visibleProperties[$index])) {
173
			if (is_array($this->visibleProperties[$index])) {
174
				$this->visibleProperties[$index] = JArray::sortAssociative($this->visibleProperties[$index], $array);
175
			}
176
		}
177
		return $this;
178
	}
179
180
	public function insertInField($index, $field, $key = null) {
181
		$vb = $this->visibleProperties;
182
		if (isset($vb[$index])) {
183
			if (isset($key)) {
184
				if (\is_array($vb[$index])) {
185
					$this->visibleProperties[$index][$key] = $field;
186
				} else {
187
					$this->visibleProperties[$index] = [
188
						$vb[$index],
189
						$key => $field
190
					];
191
				}
192
			} else {
193
				if (\is_array($vb[$index])) {
194
					$this->visibleProperties[$index][] = $field;
195
				} else {
196
					$this->visibleProperties[$index] = [
197
						$vb[$index],
198
						$field
199
					];
200
				}
201
			}
202
		} else {
203
			return $this->insertField($index, $field);
204
		}
205
		return $this;
206
	}
207
208
	public function addField($field, $key = null) {
209
		if (isset($key)) {
210
			$this->visibleProperties[] = [
211
				$key => $field
212
			];
213
		} else {
214
			$this->visibleProperties[] = $field;
215
		}
216
		return $this;
217
	}
218
219
	public function addFields($fields) {
220
		$this->visibleProperties = \array_merge($this->visibleProperties, $fields);
221
		return $this;
222
	}
223
224
	public function count() {
225
		return \sizeof($this->properties);
226
	}
227
228
	public function visiblePropertiesCount() {
229
		return \sizeof($this->visibleProperties);
230
	}
231
232
	public function getProperty($index) {
233
		return $this->properties[$index];
234
	}
235
236
	public function getFieldName($index) {
237
		$property = $this->getProperty($index);
238
		if ($property instanceof \ReflectionProperty) {
239
			$result = $property->getName();
240
		} elseif (\is_callable($property)) {
241
			$result = $this->visibleProperties[$index];
242
		} else {
243
			$result = $property;
244
		}
245
		return $result;
246
	}
247
248
	protected function showableProperty(\ReflectionProperty $rProperty) {
249
		return JString::startswith($rProperty->getName(), "_") === false;
250
	}
251
252
	public function setInstance($instance) {
253
		if (\is_string($instance) && \class_exists($instance)) {
254
			$instance = new $instance();
255
		}
256
		$this->instance = $instance;
257
		$this->properties = [];
258
		try{
259
			$this->reflect = new \ReflectionClass($instance);
260
			if (JArray::count($this->visibleProperties) === 0) {
261
				$this->properties = $this->getDefaultProperties();
262
			} else {
263
				foreach ($this->visibleProperties as $property) {
264
					$this->setInstanceProperty($property);
265
				}
266
			}
267
		}catch (\Throwable $th){
268
			
269
		}
270
		return $this;
271
	}
272
273
	private function setInstanceProperty($property) {
274
		if (\is_callable($property)) {
275
			$this->properties[] = $property;
276
		} elseif (\is_string($property)) {
277
			try {
278
				$this->_beforeAddProperty(\sizeof($this->properties), $property);
279
				$rProperty = $this->reflect->getProperty($property);
280
				$this->properties[] = $rProperty;
281
			} catch (\Exception $e) {
282
				$this->_beforeAddProperty(\sizeof($this->properties), $property);
283
				$this->properties[] = $property;
284
			}
285
		} elseif (\is_int($property)) {
286
			$props = $this->getDefaultProperties();
287
			if (isset($props[$property]))
288
				$this->properties[] = $props[$property];
289
			else
290
				$this->properties[] = $property;
291
		} else {
292
			$this->properties[] = $property;
293
		}
294
	}
295
296
	protected function getDefaultProperties() {
297
		$result = [];
298
		$properties = $this->reflect->getProperties();
299
		foreach ($properties as $property) {
300
			$showable = $this->showableProperty($property);
301
			if ($showable !== false) {
302
				$result[] = $property;
303
			}
304
		}
305
		return $result;
306
	}
307
308
	public function setVisibleProperties($visibleProperties) {
309
		$this->visibleProperties = $visibleProperties;
310
		return $this;
311
	}
312
313
	public function setValueFunction($index, $callback) {
314
		$this->values[$index] = $callback;
315
		return $this;
316
	}
317
318
	public function setIdentifierFunction($callback) {
319
		$this->values["identifier"] = $callback;
320
		return $this;
321
	}
322
323
	public static function setIndex($index) {
324
		self::$index = $index;
325
	}
326
327
	public function getProperties() {
328
		return $this->properties;
329
	}
330
331
	public function getCaption($index) {
332
		if (isset($this->captions[$index])) {
333
			return $this->captions[$index];
334
		}
335
		if ($this->properties[$index] instanceof \ReflectionProperty)
336
			return $this->properties[$index]->getName();
337
		elseif (\is_callable($this->properties[$index]))
338
			return "";
339
		else
340
			return $this->properties[$index];
341
	}
342
343
	public function getCaptions() {
344
		$hasGroupby = is_array($this->groupByFields);
345
		$count = $this->count();
346
		$moreAdded = false;
347
		if (isset($this->captions)) {
348
			$captions = \array_values($this->captions);
349
			$gbSize = $hasGroupby ? sizeof($this->groupByFields) : 0;
350
			$captionsSize = \sizeof($captions);
351
			for ($i = $captionsSize; $i < $count - $gbSize; $i ++) {
352
				$captions[] = "";
353
				$moreAdded = true;
354
			}
355
		} else {
356
			$captions = [];
357
			$index = 0;
358
			while ($index < $count) {
359
				$captions[] = $this->getCaption($index ++);
360
			}
361
		}
362
		if ($hasGroupby && sizeof($captions) >= $count && ! $moreAdded) {
363
			$captions = JArray::removeByKeys($captions, $this->groupByFields);
364
		}
365
		if (isset($this->captionCallback) && \is_callable($this->captionCallback)) {
366
			$callback = $this->captionCallback;
367
			$callback($captions, $this->instance);
368
		}
369
		return $captions;
370
	}
371
372
	public function setCaption($index, $caption) {
373
		if (isset($this->captions) === false)
374
			$this->captions = [];
375
		$this->captions[$index] = $caption;
376
		return $this;
377
	}
378
379
	public function setCaptions($captions) {
380
		$this->captions = $captions;
381
		return $this;
382
	}
383
384
	/**
385
	 * Associates a $callback function after the compilation of the field at $index position
386
	 * The $callback function can take the following arguments : $field=>the compiled field, $instance : the active instance of the object, $index: the field position
387
	 *
388
	 * @param int $index
389
	 *        	postion of the compiled field
390
	 * @param callable $callback
391
	 *        	function called after the field compilation
392
	 * @return InstanceViewer
393
	 */
394
	public function afterCompile($index, $callback) {
395
		$this->afterCompile[$index] = $callback;
396
		return $this;
397
	}
398
399
	/**
400
	 * Defines a callback function to call for modifying captions
401
	 * function parameters are $captions: the captions to modify and $instance: the active model instance
402
	 *
403
	 * @param callable $captionCallback
404
	 * @return \Ajax\semantic\widgets\base\InstanceViewer
405
	 */
406
	public function setCaptionCallback($captionCallback) {
407
		$this->captionCallback = $captionCallback;
408
		return $this;
409
	}
410
411
	/**
412
	 * Defines the default function which displays fields value
413
	 *
414
	 * @param callable $defaultValueFunction
415
	 *        	function parameters are : $name : the field name, $value : the field value ,$index : the field index, $instance : the active instance of model
416
	 * @return \Ajax\semantic\widgets\base\InstanceViewer
417
	 */
418
	public function setDefaultValueFunction($defaultValueFunction) {
419
		$this->defaultValueFunction = $defaultValueFunction;
420
		return $this;
421
	}
422
423
	public function getVisibleProperties() {
424
		return $this->visibleProperties;
425
	}
426
427
	public function getSimpleProperties() {
428
		return array_filter($this->visibleProperties, function ($item) {
429
			return ! (is_array($item) || is_object($item));
430
		});
431
	}
432
433
	/**
434
	 *
435
	 * @return callable
436
	 */
437
	public function getDefaultValueFunction() {
438
		return $this->defaultValueFunction;
439
	}
440
441
	/**
442
	 *
443
	 * @return mixed
444
	 */
445
	public function getGroupByFields() {
446
		return $this->groupByFields;
447
	}
448
449
	/**
450
	 *
451
	 * @param mixed $groupByFields
452
	 */
453
	public function setGroupByFields($groupByFields) {
454
		$this->groupByFields = $groupByFields;
455
	}
456
	
457
	public function addGroupBy($groupByField){
458
		$this->groupByFields[]=$groupByField;
459
	}
460
461
	public function getGroupByFieldsCount() {
462
		if (is_array($this->groupByFields)) {
463
			return sizeof($this->groupByFields);
464
		}
465
		return 0;
466
	}
467
}
468