Passed
Push — master ( 28f925...e24b4a )
by Jean-Christophe
02:14
created

InstanceViewer   F

Complexity

Total Complexity 78

Size/Duplication

Total Lines 346
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 346
rs 2.1126
c 0
b 0
f 0
wmc 78

38 Methods

Rating   Name   Duplication   Size   Complexity  
A getValues() 0 8 2
A _beforeAddProperty() 0 1 1
A getValue() 0 3 1
A getIdentifier() 0 11 4
A swapFields() 0 5 2
A __construct() 0 9 2
A removeField() 0 5 1
A moveFieldTo() 0 5 2
A setIdentifierFunction() 0 3 1
A getFieldName() 0 10 3
A visiblePropertiesCount() 0 2 1
A setDefaultValueFunction() 0 3 1
A getVisibleProperties() 0 2 1
B getCaptions() 0 20 6
A count() 0 2 1
A setValueFunction() 0 3 1
A getDefaultProperties() 0 10 3
A addFields() 0 3 1
A setCaption() 0 5 2
A setIndex() 0 2 1
A setInstance() 0 15 4
A insertField() 0 3 1
A addField() 0 3 1
A showableProperty() 0 2 1
A setVisibleProperties() 0 3 1
A getCaption() 0 10 4
B setInstanceProperty() 0 20 6
A setCaptions() 0 3 1
A insertInField() 0 12 3
A _postGetValue() 0 12 4
A afterCompile() 0 3 1
A setCaptionCallback() 0 3 1
A getProperties() 0 2 1
A _getDefaultValue() 0 3 1
A getProperty() 0 2 1
A _getPropertyValue() 0 3 1
B _getValue() 0 20 8
A getDefaultValueFunction() 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
use Ajax\service\JString;
4
use Ajax\service\JArray;
5
use Ajax\service\JReflection;
6
7
class InstanceViewer {
8
	protected $widgetIdentifier;
9
	protected $instance;
10
	protected $reflect;
11
	protected $properties;
12
	protected $visibleProperties;
13
	protected $values;
14
	protected $afterCompile;
15
	protected $captions;
16
	protected $captionCallback;
17
	protected $defaultValueFunction;
18
19
20
	public static $index=0;
21
22
	public function __construct($identifier,$instance=NULL,$captions=NULL){
23
		$this->widgetIdentifier=$identifier;
24
		$this->values=[];
25
		$this->afterCompile=[];
26
		if(isset($instance))
27
			$this->setInstance($instance);
28
		$this->setCaptions($captions);
29
		$this->captionCallback=NULL;
30
		$this->defaultValueFunction=function($name,$value){return $value;};
31
	}
32
33
	public function moveFieldTo($from,$to){
34
		if(JArray::moveElementTo($this->visibleProperties, $from, $to)){
35
			return JArray::moveElementTo($this->values, $from, $to);
36
		}
37
		return false;
38
	}
39
40
	public function swapFields($index1,$index2){
41
		if(JArray::swapElements($this->visibleProperties, $index1, $index2)){
42
			return JArray::swapElements($this->values, $index1, $index2);
43
		}
44
		return false;
45
	}
46
47
	public function removeField($index){
48
		\array_splice($this->visibleProperties,$index,1);
49
		\array_splice($this->values,$index,1);
50
		\array_splice($this->captions,$index,1);
51
		return $this;
52
	}
53
54
	public function getValues(){
55
		$values=[];
56
		$index=0;
57
		$count=$this->count();
58
		while($index<$count){
59
			$values[]=$this->getValue($index++);
60
		}
61
		return $values;
62
	}
63
64
	public function getIdentifier($index=NULL){
65
		if(!isset($index))
66
			$index=self::$index;
67
		$value=$index;
68
		if(isset($this->values["identifier"])){
69
			if(\is_string($this->values["identifier"]))
70
				$value=JReflection::callMethod($this->instance, $this->values["identifier"], []);
71
			else
72
				$value=$this->values["identifier"]($index,$this->instance);
73
		}
74
		return $value;
75
	}
76
77
	public function getValue($index){
78
		$property=$this->properties[$index];
79
		return $this->_getValue($property, $index);
80
	}
81
82
	protected function _beforeAddProperty($index,&$field){
83
84
	}
85
86
	protected function _getDefaultValue($name,$value,$index){
87
		$func=$this->defaultValueFunction;
88
		return $func($name,$value,$index,$this->instance);
89
	}
90
91
	protected function _getPropertyValue(\ReflectionProperty $property){
92
		$property->setAccessible(true);
93
		return $property->getValue($this->instance);
94
	}
95
96
	protected function _getValue($property,$index){
97
		$value=null;
98
		$propertyName=$property;
99
		if($property instanceof \ReflectionProperty){
100
			$value=$this->_getPropertyValue($property);
101
			$propertyName=$property->getName();
102
		}elseif(\is_callable($property) && array_search($property, ["system"])===false)
103
			$value=$property($this->instance);
104
		elseif(\is_array($property)){
105
			$values=\array_map(function($v) use ($index){return $this->_getValue($v, $index);}, $property);
106
			$value=\implode("", $values);
107
		}elseif(\is_string($property)){
108
			$value=$property;
109
			if(isset($this->instance->{$property})){
110
				$value=$this->instance->{$property};
111
			}elseif(\method_exists($this->instance, $getter=JReflection::getterName($property))){
112
				$value=JReflection::callMethod($this->instance, $getter, []);
113
			}
114
		}
115
		return $this->_postGetValue($index, $propertyName, $value);
116
	}
117
118
	protected function _postGetValue($index,$propertyName,$value){
119
		if(isset($this->values[$index])){
120
			$value= $this->values[$index]($value,$this->instance,$index,self::$index);
121
		}else{
122
			$value=$this->_getDefaultValue($propertyName,$value, $index);
123
		}
124
		if(isset($this->afterCompile[$index])){
125
			if(\is_callable($this->afterCompile[$index])){
126
				$this->afterCompile[$index]($value,$this->instance,self::$index);
127
			}
128
		}
129
		return $value;
130
	}
131
132
	public function insertField($index,$field){
133
		array_splice( $this->visibleProperties, $index, 0, $field );
134
		return $this;
135
	}
136
137
	public function insertInField($index,$field){
138
		$vb=$this->visibleProperties;
139
		if(isset($vb[$index])){
140
			if(\is_array($vb[$index])){
141
				$this->visibleProperties[$index][]=$field;
142
			}else{
143
				$this->visibleProperties[$index]=[$vb[$index],$field];
144
			}
145
		}else{
146
			return $this->insertField($index, $field);
147
		}
148
		return $this;
149
	}
150
151
	public function addField($field){
152
		$this->visibleProperties[]=$field;
153
		return $this;
154
	}
155
156
	public function addFields($fields){
157
		$this->visibleProperties=\array_merge($this->visibleProperties,$fields);
158
		return $this;
159
	}
160
161
	public function count(){
162
		return \sizeof($this->properties);
163
	}
164
165
	public function visiblePropertiesCount(){
166
		return \sizeof($this->visibleProperties);
167
	}
168
169
	public function getProperty($index){
170
		return $this->properties[$index];
171
	}
172
173
	public function getFieldName($index){
174
		$property=$this->getProperty($index);
175
		if($property instanceof \ReflectionProperty){
176
			$result=$property->getName();
177
		}elseif(\is_callable($property)){
178
			$result=$this->visibleProperties[$index];
179
		}else{
180
			$result=$property;
181
		}
182
		return $result;
183
	}
184
185
186
	protected function showableProperty(\ReflectionProperty $rProperty){
187
		return JString::startswith($rProperty->getName(),"_")===false;
188
	}
189
190
	public function setInstance($instance) {
191
		if(\is_string($instance)){
192
			$instance=new $instance();
193
		}
194
		$this->instance=$instance;
195
		$this->properties=[];
196
		$this->reflect=new \ReflectionClass($instance);
197
		if(JArray::count($this->visibleProperties)===0){
198
			$this->properties=$this->getDefaultProperties();
199
		}else{
200
			foreach ($this->visibleProperties as $property){
201
				$this->setInstanceProperty($property);
202
			}
203
		}
204
		return $this;
205
	}
206
207
	private function setInstanceProperty($property){
208
		if(\is_callable($property)){
209
			$this->properties[]=$property;
210
		}elseif(\is_string($property)){
211
			try{
212
				$this->_beforeAddProperty(\sizeof($this->properties), $property);
213
				$rProperty=$this->reflect->getProperty($property);
214
				$this->properties[]=$rProperty;
215
			}catch(\Exception $e){
216
				$this->_beforeAddProperty(\sizeof($this->properties), $property);
217
				$this->properties[]=$property;
218
			}
219
		}elseif(\is_int($property)){
220
			$props=$this->getDefaultProperties();
221
			if(isset($props[$property]))
222
				$this->properties[]=$props[$property];
223
				else
224
					$this->properties[]=$property;
225
		}else{
226
			$this->properties[]=$property;
227
		}
228
	}
229
230
	protected function getDefaultProperties(){
231
		$result=[];
232
		$properties=$this->reflect->getProperties();
233
		foreach ($properties as $property){
234
			$showable=$this->showableProperty($property);
235
			if($showable!==false){
236
				$result[]=$property;
237
			}
238
		}
239
		return $result;
240
	}
241
242
	public function setVisibleProperties($visibleProperties) {
243
		$this->visibleProperties=$visibleProperties;
244
		return $this;
245
	}
246
247
	public function setValueFunction($index,$callback){
248
		$this->values[$index]=$callback;
249
		return $this;
250
	}
251
252
	public function setIdentifierFunction($callback){
253
		$this->values["identifier"]=$callback;
254
		return $this;
255
	}
256
257
	public static function setIndex($index) {
258
		self::$index=$index;
259
	}
260
261
	public function getProperties() {
262
		return $this->properties;
263
	}
264
265
	public function getCaption($index){
266
		if(isset($this->captions[$index])){
267
			return $this->captions[$index];
268
		}
269
		if($this->properties[$index] instanceof \ReflectionProperty)
270
			return $this->properties[$index]->getName();
271
		elseif(\is_callable($this->properties[$index]))
272
			return "";
273
		else
274
			return $this->properties[$index];
275
	}
276
277
	public function getCaptions(){
278
		$count=$this->count();
279
		if(isset($this->captions)){
280
			$captions= \array_values($this->captions);
281
			$captionsSize=\sizeof($captions);
282
			for($i=$captionsSize;$i<$count;$i++){
283
				$captions[]="";
284
			}
285
		}else{
286
			$captions=[];
287
			$index=0;
288
			while($index<$count){
289
				$captions[]=$this->getCaption($index++);
290
			}
291
		}
292
		if(isset($this->captionCallback) && \is_callable($this->captionCallback)){
293
			$callback=$this->captionCallback;
294
			$callback($captions,$this->instance);
295
		}
296
		return $captions;
297
	}
298
299
	public function setCaption($index,$caption){
300
		if(isset($this->captions)===false)
301
			$this->captions=[];
302
		$this->captions[$index]=$caption;
303
		return $this;
304
	}
305
306
	public function setCaptions($captions) {
307
		$this->captions=$captions;
308
		return $this;
309
	}
310
311
	/**
312
	 * Associates a $callback function after the compilation of the field at $index position
313
	 * The $callback function can take the following arguments : $field=>the compiled field, $instance : the active instance of the object, $index: the field position
314
	 * @param int $index postion of the compiled field
315
	 * @param callable $callback function called after the field compilation
316
	 * @return InstanceViewer
317
	 */
318
	public function afterCompile($index,$callback){
319
		$this->afterCompile[$index]=$callback;
320
		return $this;
321
	}
322
323
	/**
324
	 * Defines a callback function to call for modifying captions
325
	 * function parameters are $captions: the captions to modify and $instance: the active model instance
326
	 * @param callable $captionCallback
327
	 * @return \Ajax\semantic\widgets\base\InstanceViewer
328
	 */
329
	public function setCaptionCallback($captionCallback) {
330
		$this->captionCallback=$captionCallback;
331
		return $this;
332
	}
333
334
	/**
335
	 * Defines the default function which displays fields value
336
	 * @param callable $defaultValueFunction function parameters are : $name : the field name, $value : the field value ,$index : the field index, $instance : the active instance of model
337
	 * @return \Ajax\semantic\widgets\base\InstanceViewer
338
	 */
339
	public function setDefaultValueFunction($defaultValueFunction) {
340
		$this->defaultValueFunction=$defaultValueFunction;
341
		return $this;
342
	}
343
344
	public function getVisibleProperties() {
345
		return $this->visibleProperties;
346
	}
347
348
	/**
349
	 * @return callable
350
	 */
351
	public function getDefaultValueFunction() {
352
		return $this->defaultValueFunction;
353
	}
354
}
355