absences_client   B
last analyzed

Complexity

Total Complexity 46

Size/Duplication

Total Lines 409
Duplicated Lines 2.44 %

Coupling/Cohesion

Components 1
Dependencies 10

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 10
loc 409
rs 8.3999
wmc 46
lcom 1
cbo 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
D getData() 0 84 13
B getCachedData() 0 44 6
C getRight() 0 86 9
B getValueAccordingToDbCharset() 0 17 5
C addRight() 10 66 8
B updateRight() 0 28 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

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:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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

1
<?php
2
//-------------------------------------------------------------------------
3
// OVIDENTIA http://www.ovidentia.org
4
// Ovidentia is free software; you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation; either version 2, or (at your option)
7
// any later version.
8
//
9
// This program is distributed in the hope that it will be useful, but
10
// WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
// See the GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program; if not, write to the Free Software
16
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17
// USA.
18
//-------------------------------------------------------------------------
19
/**
20
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
21
 * @copyright Copyright (c) 2006 by CANTICO ({@link http://www.cantico.fr})
22
 */
23
24
require_once $GLOBALS['babInstallPath'].'utilit/urlincl.php';
25
require_once dirname(__FILE__).'/sync_items.class.php';
26
27
28
/**
29
 * HTTP client for synchronization
30
 *
31
 */
32
class absences_client
33
{
34
35
36
	/**
37
	 * 
38
	 * @var absences_sync_items
39
	 */
40
	private $sync_items;
41
	
42
	private $uuid_index = null;
43
44
45
	/**
46
	 * 
47
	 */
48
	public function __construct()
49
	{
50
51
		$this->sync_items = new absences_sync_items();
52
	}
53
	
54
	
55
56
57
58
	/**
59
	 * Get data from server with a query
60
	 * 
61
	 * @param string	$lastmodified			NULL = force update
62
	 * 
63
	 * @return array | null
64
	 */
65
	protected function getData($lastmodified = null)
66
	{
67
		
68
		
69
		$url = absences_getVacationOption('sync_url');
70
		$nickname = absences_getVacationOption('sync_nickname');
71
		$password = absences_getVacationOption('sync_password');
72
73
		if (empty($url) || empty($nickname) || empty($password))
74
		{
75
			throw new Exception('Missing server URL or nickname or password in configuration');
76
		}
77
		
78
		if ('/' !== substr($url, -1, 1))
79
		{
80
			$url .= '/';
81
		}
82
		
83
		$url .= 'index.php?addon=absences.server';
84
85
		$ch = curl_init();
86
		curl_setopt($ch, CURLOPT_URL, $url);
87
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
88
		curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
89
		curl_setopt($ch, CURLOPT_USERPWD, sprintf('%s:%s', $nickname, $password));
90
		if ($lastmodified !== null)
91
		{
92
			bab_debug(sprintf('Local lastmodified date used in the If-modified-since header %s', $lastmodified));
93
			
94
			$headers = array(
95
					'If-modified-since: '.gmdate("D, d M Y H:i:s", bab_mktime($lastmodified)) . " GMT"
96
			);
97
			curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
98
		} else {
99
			$user_id = bab_getUserId();
100
			$user_name = $user_id ? bab_getUserName($user_id) : 'Anonymous';
101
			bab_debug(sprintf('Force update by "%s" : do not get the last modification date', $user_name));
102
		}
103
104
		$return = curl_exec($ch);
105
106
		if (false === $return)
107
		{
108
			throw new Exception(curl_error($ch));
109
		}
110
	
111
112
113
		if (304 === curl_getinfo($ch, CURLINFO_HTTP_CODE))
114
		{
115
			bab_debug('Received 304');
116
			$arr_return = null;
117
			
118
		} else {
119
			
120
			$memory_limit = (64*1024*1024) + (strlen($return) * 10);
121
			ini_set('memory_limit', $memory_limit);
122
			
123
			$arr_return = unserialize($return);
124
		
125
			if (false === $arr_return)
126
			{
127
				throw new Exception('Server : '.$return);
128
			}
129
			
130
			if ($content_type = curl_getinfo($ch, CURLINFO_CONTENT_TYPE))
131
			{
132
				if (preg_match('/charset=([A-Z0-9\-]+)/', $content_type, $match))
133
				{
134
					if ($match[1] !== bab_Charset::getIso())
135
					{
136
						$arr_return = $this->getValueAccordingToDbCharset('', $arr_return, $match[1]);
137
					}
138
				}
139
			}
140
			
141
		}
142
143
		curl_close($ch);
144
145
146
147
		return $arr_return;
148
	}
149
	
150
	
151
	
152
	/**
153
	 * Query with a static cache file 
154
	 * 
155
	 * 60 secondes de cache par la duree 
156
	 * au dela la date de derniere mise a jour est verifiee sur le serveur
157
	 * 
158
	 * @throws Exception
159
	 * 
160
	 * @return array
161
	 */
162
	public function getCachedData()
163
	{
164
		$addon = bab_getAddonInfosInstance('absences');
165
		$cachefile = new bab_Path($addon->getUploadPath());
166
		$cachefile->createDir();
167
		
168
		$cachefile->push('server_data');
169
		
170
		if ($cachefile->fileExists())
171
		{
172
			$lastupdate = date('Y-m-d H:i:s', filemtime($cachefile->tostring()));
173
			bab_debug('Cache last update '.$lastupdate);
174
		} else {
175
			$lastupdate = null;
176
		}
177
		
178
		
179
		if (!isset($lastupdate) || (time() - bab_mktime($lastupdate)) > 60)
180
		{
181
			bab_debug('Get data from server');
182
			$data = $this->getData($lastupdate);
183
			if (null !== $data)
184
			{
185
				file_put_contents($cachefile->tostring(), serialize($data));
186
				return $data;
187
			}
188
			
189
			bab_debug('Server return null (304)');
190
		}
191
		
192
		
193
		// 304 not modified || not timed out
194
		
195
		bab_debug('Get data from cache');
196
		$data = file_get_contents($cachefile->tostring());
197
		$data = unserialize($data);
198
		
199
		if (false === $data)
200
		{
201
			$cachefile->delete();
202
		}
203
		
204
		return $data;
205
	}
206
	
207
	
208
	
209
	
210
	
211
	/**
212
	 * Get shared right with all depencies as objects
213
	 * @param string $uuid
214
	 * @return absences_Right
215
	 */
216
	public function getRight($uuid)
217
	{
218
		if (!isset($this->uuid_index))
219
		{
220
			$this->uuid_index = array();
221
			$data = $this->getCachedData();
222
			
223
			require_once dirname(__FILE__).'/right_rule.class.php';
224
			require_once dirname(__FILE__).'/right_cet.class.php';
225
			require_once dirname(__FILE__).'/right_inperiod.class.php';
226
			
227
			
228
			foreach($data as $row)
229
			{
230
				$right_row = $row['absences_rights'];
231
				
232
				$right_row['id'] = null;
233
				$right = new absences_Right(null);
234
				$right->setRow($right_row);
235
				$this->uuid_index[$right_row['uuid']] = $right;
236
				
237
				
238
				$type_row = $row['absences_types'];
239
				$type_row['id'] = null;
240
				$type = new absences_Type(null);
241
				$type->setRow($type_row);
242
				$right->setType($type);
243
				
244
				$rules_row = $row['absences_rights_rules'];
245
				$rules_row['id'] = null;
246
				$rules = new absences_RightRule();
247
				$rules->setRow($rules_row);
248
				$right->setRightRule($rules);
249
				
250
				if (empty($row['rules_type']))
251
				{
252
					$rules_type_row = $row['rules_type'];
253
					$rules_type_row['id'] = null;
254
					$rules_type = new absences_Type(null);
255
					$rules_type->setRow($rules_type_row);
256
					$rules->setType($rules_type);
257
				}
258
				
259
				
260
				if (!empty($row['absences_rights_cet']))
261
				{
262
					$cet_row = $row['absences_rights_cet'];
263
					$cet_row['id'] = null;
264
					$cet = new absences_RightCet();
265
					$cet->setRow($cet_row);
266
					$right->setRightCet($cet);
267
				}
268
				
269
				if (!empty($row['absences_rights_inperiod']))
270
				{
271
					foreach($row['absences_rights_inperiod'] as $inperiod_row)
272
					{
273
						$inperiod_row['id'] = null;
274
						$inperiod = new absences_RightInPeriod();
275
						$inperiod->setRow($inperiod_row);
276
						$right->addInPeriod($inperiod);
277
					}
278
				}
279
				
280
				
281
				if (!empty($row['absences_rgroup']))
282
				{
283
					$rgroup_row = $row['absences_rgroup'];
284
					$rgroup_row['id'] = null;
285
					$rgroup = new absences_Rgroup(null);
286
					$rgroup->setRow($rgroup_row);
287
					$right->setRgroup($rgroup);
288
				}
289
			}
290
			
291
		}
292
		
293
		
294
		if (!isset($this->uuid_index[$uuid]))
295
		{
296
			return null;
297
		}
298
		
299
		
300
		return $this->uuid_index[$uuid];
301
	}
302
	
303
	
304
	
305
	
306
	/**
307
	 * Convert charset for text values in array
308
	 * ignore keys begin with __ (binary data)
309
	 * 
310
	 * @param string $keyname
311
	 * @param string $input
312
	 * @param string $sStringIsoCharset
313
	 * 
314
	 * @return string
315
	 */
316
	protected function getValueAccordingToDbCharset($keyname, $input, $sStringIsoCharset)
317
	{
318
		if (bab_charset::getIso() === $sStringIsoCharset || 0 === strpos($keyname, '__')) {
319
			return $input;
320
		}
321
		
322
		if (is_array($input)) {
323
			foreach($input as $k => $data) {
324
				$input[$k] = $this->getValueAccordingToDbCharset($k, $data, $sStringIsoCharset);
325
			}
326
		
327
			return $input;
328
		}
329
		
330
331
		return mb_convert_encoding($input, bab_charset::getIso(), $sStringIsoCharset);
332
	}
333
	
334
	
335
336
337
338
	/**
339
	 * 
340
	 * @param string $uuid
341
	 * @return absences_Right
342
	 */
343
	public function addRight($uuid)
344
	{
345
		
346
		global $babDB;
347
		$right = $this->getRight($uuid);
348
		
349
		$type = $right->getType();
350
		$rgroup = $right->getRgroup();
351
		$right->id_type = 0;
352
		$right->id_rgroup = 0;
353
		
354
		// search a matching type
355
		$res = $babDB->db_query('SELECT id FROM absences_types WHERE name LIKE \''.$babDB->db_escape_like($type->name).'\'');
356 View Code Duplication
		if (0 !== $babDB->db_num_rows($res))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
357
		{
358
			$arr = $babDB->db_fetch_assoc($res);
359
			$right->id_type = $arr['id'];
360
		}
361
		
362
		// search a matching rgroup
363
		$res = $babDB->db_query('SELECT id FROM absences_rgroup WHERE name LIKE \''.$babDB->db_escape_like($rgroup->name).'\'');
364 View Code Duplication
		if (0 !== $babDB->db_num_rows($res))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
365
		{
366
			$arr = $babDB->db_fetch_assoc($res);
367
			$right->id_rgroup = $arr['id'];
368
		}
369
		
370
		
371
		$right->sync_status = 1;
372
		$right->sync_update = date('Y-m-d H:i:s');
373
		$right->insert();
374
		
375
		foreach($right->getInperiodRules() as $inperiod)
376
		{
377
			$inperiod->save();
378
		}
379
		
380
		$rule = $right->getRightRule();
381
		if ($rule->getRow())
382
		{
383
			$rule->trigger_type = 0;
384
			$type = $rule->getType();
385
			if (isset($type))
386
			{
387
				// search a matching type
388
				$res = $babDB->db_query('SELECT id FROM absences_types WHERE name LIKE \''.$babDB->db_escape_like($type->name).'\'');
389
				if (0 !== $babDB->db_num_rows($res))
390
				{
391
					$arr = $babDB->db_fetch_assoc($res);
392
					$rule->trigger_type = $arr['id'];
393
				}
394
			}
395
			
396
			$rule->id_right = $right->id;
397
			$rule->insert();
398
		}
399
		
400
		$cet = $right->getRightCet();
401
		if ($cet->getRow())
402
		{
403
			$cet->id_right = $right->id;
404
			$cet->insert();
405
		}
406
		
407
		return $right;
408
	}
409
	
410
	
411
	public function updateRight($uuid)
412
	{
413
		global $babDB;
414
		$right = $this->getRight($uuid);
415
		$right->sync_status = 1;
416
		$right->sync_update = date('Y-m-d H:i:s');
417
		$right->update();
418
		
419
		
420
		foreach($right->getInperiodRules() as $inperiod)
421
		{
422
			$inperiod->save();
423
		}
424
		
425
		$rule = $right->getRightRule();
426
		if ($rule->getRow())
427
		{
428
			$rule->id_right = $right->id;
429
			$rule->update();
430
		}
431
		
432
		$cet = $right->getRightCet();
433
		if ($cet->getRow())
434
		{
435
			$cet->id_right = $right->id;
436
			$cet->update();
437
		}
438
	}
439
440
}
441
442
443