Test Failed
Push — master ( 3c3be4...ec7459 )
by Ricardo Jesus Ruiz
02:59
created

CI_DB_utility   B

Complexity

Total Complexity 53

Size/Duplication

Total Lines 366
Duplicated Lines 8.74 %

Importance

Changes 0
Metric Value
dl 32
loc 366
rs 7.4757
c 0
b 0
f 0
wmc 53

9 Methods

Rating   Name   Duplication   Size   Complexity  
B list_databases() 0 26 6
A __construct() 0 3 1
C xml_from_result() 0 35 7
B optimize_database() 0 27 5
A repair_table() 15 15 4
A optimize_table() 15 15 4
B csv_from_result() 0 20 6
F backup() 0 100 19
A database_exists() 0 3 1

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

1
<?php
2
/**
3
 * CodeIgniter
4
 *
5
 * An open source application development framework for PHP
6
 *
7
 * This content is released under the MIT License (MIT)
8
 *
9
 * Copyright (c) 2014 - 2017, British Columbia Institute of Technology
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
 * of this software and associated documentation files (the "Software"), to deal
13
 * in the Software without restriction, including without limitation the rights
14
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
 * copies of the Software, and to permit persons to whom the Software is
16
 * furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies or substantial portions of the Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
 * THE SOFTWARE.
28
 *
29
 * @package	CodeIgniter
30
 * @author	EllisLab Dev Team
31
 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (https://ellislab.com/)
32
 * @copyright	Copyright (c) 2014 - 2017, British Columbia Institute of Technology (http://bcit.ca/)
33
 * @license	http://opensource.org/licenses/MIT	MIT License
34
 * @link	https://codeigniter.com
35
 * @since	Version 1.0.0
36
 * @filesource
37
 */
38
namespace Rioxygen\CiCoreDatabase;
39
40
/**
41
 * Database Utility Class
42
 *
43
 * @category	Database
44
 * @author		EllisLab Dev Team
45
 * @link		https://codeigniter.com/user_guide/database/
46
 */
47
abstract class CI_DB_utility {
48
49
	/**
50
	 * Database object
51
	 *
52
	 * @var	object
53
	 */
54
	protected $db;
55
56
	// --------------------------------------------------------------------
57
58
	/**
59
	 * List databases statement
60
	 *
61
	 * @var	string
62
	 */
63
	protected $_list_databases		= FALSE;
64
65
	/**
66
	 * OPTIMIZE TABLE statement
67
	 *
68
	 * @var	string
69
	 */
70
	protected $_optimize_table	= FALSE;
71
72
	/**
73
	 * REPAIR TABLE statement
74
	 *
75
	 * @var	string
76
	 */
77
	protected $_repair_table	= FALSE;
78
79
	// --------------------------------------------------------------------
80
81
	/**
82
	 * Class constructor
83
	 *
84
	 * @param	object	&$db	Database object
85
	 * @return	void
86
	 */
87
	public function __construct(&$db)
88
	{
89
		$this->db =& $db;
90
	}
91
92
	// --------------------------------------------------------------------
93
94
	/**
95
	 * List databases
96
	 *
97
	 * @return	array
98
	 */
99
	public function list_databases()
100
	{
101
		// Is there a cached result?
102
		if (isset($this->db->data_cache['db_names']))
103
		{
104
			return $this->db->data_cache['db_names'];
105
		}
106
		elseif ($this->_list_databases === FALSE)
107
		{
108
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
109
		}
110
111
		$this->db->data_cache['db_names'] = array();
112
113
		$query = $this->db->query($this->_list_databases);
114
		if ($query === FALSE)
115
		{
116
			return $this->db->data_cache['db_names'];
117
		}
118
119
		for ($i = 0, $query = $query->result_array(), $c = count($query); $i < $c; $i++)
120
		{
121
			$this->db->data_cache['db_names'][] = current($query[$i]);
122
		}
123
124
		return $this->db->data_cache['db_names'];
125
	}
126
127
	// --------------------------------------------------------------------
128
129
	/**
130
	 * Determine if a particular database exists
131
	 *
132
	 * @param	string	$database_name
133
	 * @return	bool
134
	 */
135
	public function database_exists($database_name)
136
	{
137
		return in_array($database_name, $this->list_databases());
138
	}
139
140
	// --------------------------------------------------------------------
141
142
	/**
143
	 * Optimize Table
144
	 *
145
	 * @param	string	$table_name
146
	 * @return	mixed
147
	 */
148 View Code Duplication
	public function optimize_table($table_name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
149
	{
150
		if ($this->_optimize_table === FALSE)
151
		{
152
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
153
		}
154
155
		$query = $this->db->query(sprintf($this->_optimize_table, $this->db->escape_identifiers($table_name)));
156
		if ($query !== FALSE)
157
		{
158
			$query = $query->result_array();
159
			return current($query);
160
		}
161
162
		return FALSE;
163
	}
164
165
	// --------------------------------------------------------------------
166
167
	/**
168
	 * Optimize Database
169
	 *
170
	 * @return	mixed
171
	 */
172
	public function optimize_database()
173
	{
174
		if ($this->_optimize_table === FALSE)
175
		{
176
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
177
		}
178
179
		$result = array();
180
		foreach ($this->db->list_tables() as $table_name)
181
		{
182
			$res = $this->db->query(sprintf($this->_optimize_table, $this->db->escape_identifiers($table_name)));
183
			if (is_bool($res))
184
			{
185
				return $res;
186
			}
187
188
			// Build the result array...
189
			$res = $res->result_array();
190
			$res = current($res);
191
			$key = str_replace($this->db->database.'.', '', current($res));
192
			$keys = array_keys($res);
193
			unset($res[$keys[0]]);
194
195
			$result[$key] = $res;
196
		}
197
198
		return $result;
199
	}
200
201
	// --------------------------------------------------------------------
202
203
	/**
204
	 * Repair Table
205
	 *
206
	 * @param	string	$table_name
207
	 * @return	mixed
208
	 */
209 View Code Duplication
	public function repair_table($table_name)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
210
	{
211
		if ($this->_repair_table === FALSE)
212
		{
213
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
214
		}
215
216
		$query = $this->db->query(sprintf($this->_repair_table, $this->db->escape_identifiers($table_name)));
217
		if (is_bool($query))
218
		{
219
			return $query;
220
		}
221
222
		$query = $query->result_array();
223
		return current($query);
224
	}
225
226
	// --------------------------------------------------------------------
227
228
    /**
229
     * Generate CSV from a query result object
230
     *
231
     * @param	object	$query		Query result object
232
     * @param	string	$delim		Delimiter (default: ,)
233
     * @param	string	$newline	Newline character (default: \n)
234
     * @param	string	$enclosure	Enclosure (default: ")
235
     * @return	string
236
     */
237
    public function csv_from_result($query, $delim = ',', $newline = "\n", $enclosure = '"')
238
    {
239
        if ( ! is_object($query) OR ! method_exists($query, 'list_fields')) {
240
            error_log('You must submit a valid result object');
241
        }
242
        $out = '';
243
        // First generate the headings from the table column names
244
        foreach ($query->list_fields() as $name) {
245
                $out .= $enclosure.str_replace($enclosure, $enclosure.$enclosure, $name).$enclosure.$delim;
246
        }
247
        $out = substr($out, 0, -strlen($delim)).$newline;
0 ignored issues
show
Bug introduced by
Are you sure substr($out, 0, -strlen($delim)) of type false|string can be used in concatenation? ( Ignorable by Annotation )

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

247
        $out = /** @scrutinizer ignore-type */ substr($out, 0, -strlen($delim)).$newline;
Loading history...
248
        // Next blast through the result array and build out the rows
249
        while ($row = $query->unbuffered_row('array')) {
250
            $line = array();
251
            foreach ($row as $ite) {
252
                $line[] = $enclosure.str_replace($enclosure, $enclosure.$enclosure, $item).$enclosure;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $item seems to be never defined.
Loading history...
253
            }
254
            $out .= implode($delim, $line).$newline;
255
        }
256
        return $out;
257
    }
258
259
	// --------------------------------------------------------------------
260
261
	/**
262
	 * Generate XML data from a query result object
263
	 *
264
	 * @param	object	$query	Query result object
265
	 * @param	array	$params	Any preferences
266
	 * @return	string
267
	 */
268
	public function xml_from_result($query, $params = array())
269
	{
270
		if ( ! is_object($query) OR ! method_exists($query, 'list_fields'))
271
		{
272
			error_log('You must submit a valid result object');
273
		}
274
275
		// Set our default values
276
		foreach (array('root' => 'root', 'element' => 'element', 'newline' => "\n", 'tab' => "\t") as $key => $val)
277
		{
278
			if ( ! isset($params[$key]))
279
			{
280
				$params[$key] = $val;
281
			}
282
		}
283
284
		// Create variables for convenience
285
		extract($params);
286
287
		// Load the xml helper
288
		get_instance()->load->helper('xml');
0 ignored issues
show
Bug introduced by
The function get_instance was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

288
		/** @scrutinizer ignore-call */ 
289
  get_instance()->load->helper('xml');
Loading history...
289
290
		// Generate the result
291
		$xml = '<'.$root.'>'.$newline;
292
		while ($row = $query->unbuffered_row())
293
		{
294
			$xml .= $tab.'<'.$element.'>'.$newline;
295
			foreach ($row as $key => $val)
296
			{
297
				$xml .= $tab.$tab.'<'.$key.'>'.xml_convert($val).'</'.$key.'>'.$newline;
0 ignored issues
show
Bug introduced by
The function xml_convert was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

297
				$xml .= $tab.$tab.'<'.$key.'>'./** @scrutinizer ignore-call */ xml_convert($val).'</'.$key.'>'.$newline;
Loading history...
298
			}
299
			$xml .= $tab.'</'.$element.'>'.$newline;
300
		}
301
302
		return $xml.'</'.$root.'>'.$newline;
303
	}
304
305
	// --------------------------------------------------------------------
306
307
	/**
308
	 * Database Backup
309
	 *
310
	 * @param	array	$params
311
	 * @return	string
312
	 */
313
	public function backup($params = array())
314
	{
315
		// If the parameters have not been submitted as an
316
		// array then we know that it is simply the table
317
		// name, which is a valid short cut.
318
		if (is_string($params))
319
		{
320
			$params = array('tables' => $params);
321
		}
322
323
		// Set up our default preferences
324
		$prefs = array(
325
			'tables'		=> array(),
326
			'ignore'		=> array(),
327
			'filename'		=> '',
328
			'format'		=> 'gzip', // gzip, zip, txt
329
			'add_drop'		=> TRUE,
330
			'add_insert'		=> TRUE,
331
			'newline'		=> "\n",
332
			'foreign_key_checks'	=> TRUE
333
		);
334
335
		// Did the user submit any preferences? If so set them....
336
		if (count($params) > 0)
337
		{
338
			foreach ($prefs as $key => $val)
339
			{
340
				if (isset($params[$key]))
341
				{
342
					$prefs[$key] = $params[$key];
343
				}
344
			}
345
		}
346
347
		// Are we backing up a complete database or individual tables?
348
		// If no table names were submitted we'll fetch the entire table list
349
		if (count($prefs['tables']) === 0)
350
		{
351
			$prefs['tables'] = $this->db->list_tables();
352
		}
353
354
		// Validate the format
355
		if ( ! in_array($prefs['format'], array('gzip', 'zip', 'txt'), TRUE))
356
		{
357
			$prefs['format'] = 'txt';
358
		}
359
360
		// Is the encoder supported? If not, we'll either issue an
361
		// error or use plain text depending on the debug settings
362
		if (($prefs['format'] === 'gzip' && ! function_exists('gzencode'))
363
			OR ($prefs['format'] === 'zip' && ! function_exists('gzcompress')))
364
		{
365
			if ($this->db->db_debug)
366
			{
367
				return $this->db->display_error('db_unsupported_compression');
368
			}
369
370
			$prefs['format'] = 'txt';
371
		}
372
373
		// Was a Zip file requested?
374
		if ($prefs['format'] === 'zip')
375
		{
376
			// Set the filename if not provided (only needed with Zip files)
377
			if ($prefs['filename'] === '')
378
			{
379
				$prefs['filename'] = (count($prefs['tables']) === 1 ? $prefs['tables'] : $this->db->database)
380
							.date('Y-m-d_H-i', time()).'.sql';
0 ignored issues
show
Bug introduced by
Are you sure date('Y-m-d_H-i', time()) of type false|string can be used in concatenation? ( Ignorable by Annotation )

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

380
							./** @scrutinizer ignore-type */ date('Y-m-d_H-i', time()).'.sql';
Loading history...
381
			}
382
			else
383
			{
384
				// If they included the .zip file extension we'll remove it
385
				if (preg_match('|.+?\.zip$|', $prefs['filename']))
386
				{
387
					$prefs['filename'] = str_replace('.zip', '', $prefs['filename']);
388
				}
389
390
				// Tack on the ".sql" file extension if needed
391
				if ( ! preg_match('|.+?\.sql$|', $prefs['filename']))
392
				{
393
					$prefs['filename'] .= '.sql';
394
				}
395
			}
396
397
			// Load the Zip class and output it
398
			$CI =& get_instance();
0 ignored issues
show
Bug introduced by
The function get_instance was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

398
			$CI =& /** @scrutinizer ignore-call */ get_instance();
Loading history...
399
			$CI->load->library('zip');
400
			$CI->zip->add_data($prefs['filename'], $this->_backup($prefs));
0 ignored issues
show
Bug introduced by
The method _backup() does not exist on Rioxygen\CiCoreDatabase\CI_DB_utility. Did you maybe mean backup()? ( Ignorable by Annotation )

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

400
			$CI->zip->add_data($prefs['filename'], $this->/** @scrutinizer ignore-call */ _backup($prefs));

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...
401
			return $CI->zip->get_zip();
402
		}
403
		elseif ($prefs['format'] === 'txt') // Was a text file requested?
404
		{
405
			return $this->_backup($prefs);
406
		}
407
		elseif ($prefs['format'] === 'gzip') // Was a Gzip file requested?
408
		{
409
			return gzencode($this->_backup($prefs));
410
		}
411
412
		return;
413
	}
414
415
}
416