CI_DB_forge   F
last analyzed

Complexity

Total Complexity 150

Size/Duplication

Total Lines 983
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 983
rs 1.263
c 0
b 0
f 0
wmc 150

25 Methods

Rating   Name   Duplication   Size   Complexity  
B add_field() 0 32 5
A __construct() 0 4 1
A _reset() 0 3 1
A _attr_auto_increment() 0 5 4
A _drop_table() 0 20 4
B create_database() 0 17 6
A _attr_unique() 0 5 3
D _attr_unsigned() 0 30 10
A _process_column() 0 9 1
B drop_database() 0 21 7
A _attr_type() 0 2 1
D create_table() 0 43 10
B _attr_default() 0 20 6
A drop_column() 0 9 3
F _process_fields() 0 93 23
A _process_primary_keys() 0 19 4
B add_key() 0 28 5
C rename_table() 0 27 8
B _alter_table() 0 22 5
C drop_table() 0 25 7
A _create_table_attr() 0 13 3
C modify_column() 0 31 8
C _create_table() 0 44 8
C _process_indexes() 0 31 7
D add_column() 0 32 10

How to fix   Complexity   

Complex Class

Complex classes like CI_DB_forge 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_forge, 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
39
namespace Rioxygen\CiCoreDatabase;
40
/**
41
 * Database Forge Class
42
 *
43
 * @category	Database
44
 * @author		EllisLab Dev Team
45
 * @link		https://codeigniter.com/user_guide/database/
46
 */
47
abstract class CI_DB_forge {
48
49
	/**
50
	 * Database object
51
	 *
52
	 * @var	object
53
	 */
54
	protected $db;
55
56
	/**
57
	 * Fields data
58
	 *
59
	 * @var	array
60
	 */
61
	public $fields		= array();
62
63
	/**
64
	 * Keys data
65
	 *
66
	 * @var	array
67
	 */
68
	public $keys		= array();
69
70
	/**
71
	 * Primary Keys data
72
	 *
73
	 * @var	array
74
	 */
75
	public $primary_keys	= array();
76
77
	/**
78
	 * Database character set
79
	 *
80
	 * @var	string
81
	 */
82
	public $db_char_set	= '';
83
84
	// --------------------------------------------------------------------
85
86
	/**
87
	 * CREATE DATABASE statement
88
	 *
89
	 * @var	string
90
	 */
91
	protected $_create_database	= 'CREATE DATABASE %s';
92
93
	/**
94
	 * DROP DATABASE statement
95
	 *
96
	 * @var	string
97
	 */
98
	protected $_drop_database	= 'DROP DATABASE %s';
99
100
	/**
101
	 * CREATE TABLE statement
102
	 *
103
	 * @var	string
104
	 */
105
	protected $_create_table	= "%s %s (%s\n)";
106
107
	/**
108
	 * CREATE TABLE IF statement
109
	 *
110
	 * @var	string
111
	 */
112
	protected $_create_table_if	= 'CREATE TABLE IF NOT EXISTS';
113
114
	/**
115
	 * CREATE TABLE keys flag
116
	 *
117
	 * Whether table keys are created from within the
118
	 * CREATE TABLE statement.
119
	 *
120
	 * @var	bool
121
	 */
122
	protected $_create_table_keys	= FALSE;
123
124
	/**
125
	 * DROP TABLE IF EXISTS statement
126
	 *
127
	 * @var	string
128
	 */
129
	protected $_drop_table_if	= 'DROP TABLE IF EXISTS';
130
131
	/**
132
	 * RENAME TABLE statement
133
	 *
134
	 * @var	string
135
	 */
136
	protected $_rename_table	= 'ALTER TABLE %s RENAME TO %s;';
137
138
	/**
139
	 * UNSIGNED support
140
	 *
141
	 * @var	bool|array
142
	 */
143
	protected $_unsigned		= TRUE;
144
145
	/**
146
	 * NULL value representation in CREATE/ALTER TABLE statements
147
	 *
148
	 * @var	string
149
	 */
150
	protected $_null		= '';
151
152
	/**
153
	 * DEFAULT value representation in CREATE/ALTER TABLE statements
154
	 *
155
	 * @var	string
156
	 */
157
	protected $_default		= ' DEFAULT ';
158
159
	// --------------------------------------------------------------------
160
161
	/**
162
	 * Class constructor
163
	 *
164
	 * @param	object	&$db	Database object
165
	 * @return	void
166
	 */
167
	public function __construct(&$db)
168
	{
169
		$this->db =& $db;
170
		log_message('info', 'Database Forge Class Initialized');
0 ignored issues
show
Bug introduced by
The function log_message 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

170
		/** @scrutinizer ignore-call */ 
171
  log_message('info', 'Database Forge Class Initialized');
Loading history...
171
	}
172
173
	// --------------------------------------------------------------------
174
175
	/**
176
	 * Create database
177
	 *
178
	 * @param	string	$db_name
179
	 * @return	bool
180
	 */
181
	public function create_database($db_name)
182
	{
183
		if ($this->_create_database === FALSE)
0 ignored issues
show
introduced by
The condition $this->_create_database === FALSE can never be true.
Loading history...
184
		{
185
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
186
		}
187
		elseif ( ! $this->db->query(sprintf($this->_create_database, $this->db->escape_identifiers($db_name), $this->db->char_set, $this->db->dbcollat)))
188
		{
189
			return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
190
		}
191
192
		if ( ! empty($this->db->data_cache['db_names']))
193
		{
194
			$this->db->data_cache['db_names'][] = $db_name;
195
		}
196
197
		return TRUE;
198
	}
199
200
	// --------------------------------------------------------------------
201
202
	/**
203
	 * Drop database
204
	 *
205
	 * @param	string	$db_name
206
	 * @return	bool
207
	 */
208
	public function drop_database($db_name)
209
	{
210
		if ($this->_drop_database === FALSE)
0 ignored issues
show
introduced by
The condition $this->_drop_database === FALSE can never be true.
Loading history...
211
		{
212
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
213
		}
214
		elseif ( ! $this->db->query(sprintf($this->_drop_database, $this->db->escape_identifiers($db_name))))
215
		{
216
			return ($this->db->db_debug) ? $this->db->display_error('db_unable_to_drop') : FALSE;
217
		}
218
219
		if ( ! empty($this->db->data_cache['db_names']))
220
		{
221
			$key = array_search(strtolower($db_name), array_map('strtolower', $this->db->data_cache['db_names']), TRUE);
222
			if ($key !== FALSE)
223
			{
224
				unset($this->db->data_cache['db_names'][$key]);
225
			}
226
		}
227
228
		return TRUE;
229
	}
230
231
	// --------------------------------------------------------------------
232
233
	/**
234
	 * Add Key
235
	 *
236
	 * @param	string	$key
237
	 * @param	bool	$primary
238
	 * @return	CI_DB_forge
239
	 */
240
	public function add_key($key, $primary = FALSE)
241
	{
242
		// DO NOT change this! This condition is only applicable
243
		// for PRIMARY keys because you can only have one such,
244
		// and therefore all fields you add to it will be included
245
		// in the same, composite PRIMARY KEY.
246
		//
247
		// It's not the same for regular indexes.
248
		if ($primary === TRUE && is_array($key))
0 ignored issues
show
introduced by
The condition $primary === TRUE && is_array($key) can never be true.
Loading history...
249
		{
250
			foreach ($key as $one)
251
			{
252
				$this->add_key($one, $primary);
253
			}
254
255
			return $this;
256
		}
257
258
		if ($primary === TRUE)
259
		{
260
			$this->primary_keys[] = $key;
261
		}
262
		else
263
		{
264
			$this->keys[] = $key;
265
		}
266
267
		return $this;
268
	}
269
270
	// --------------------------------------------------------------------
271
272
	/**
273
	 * Add Field
274
	 *
275
	 * @param	array	$field
276
	 * @return	CI_DB_forge
277
	 */
278
	public function add_field($field)
279
	{
280
		if (is_string($field))
0 ignored issues
show
introduced by
The condition is_string($field) can never be true.
Loading history...
281
		{
282
			if ($field === 'id')
283
			{
284
				$this->add_field(array(
285
					'id' => array(
286
						'type' => 'INT',
287
						'constraint' => 9,
288
						'auto_increment' => TRUE
289
					)
290
				));
291
				$this->add_key('id', TRUE);
292
			}
293
			else
294
			{
295
				if (strpos($field, ' ') === FALSE)
296
				{
297
					show_error('Field information is required for that operation.');
0 ignored issues
show
Bug introduced by
The function show_error 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
					/** @scrutinizer ignore-call */ 
298
     show_error('Field information is required for that operation.');
Loading history...
298
				}
299
300
				$this->fields[] = $field;
301
			}
302
		}
303
304
		if (is_array($field))
0 ignored issues
show
introduced by
The condition is_array($field) can never be false.
Loading history...
305
		{
306
			$this->fields = array_merge($this->fields, $field);
307
		}
308
309
		return $this;
310
	}
311
312
	// --------------------------------------------------------------------
313
314
	/**
315
	 * Create Table
316
	 *
317
	 * @param	string	$table		Table name
318
	 * @param	bool	$if_not_exists	Whether to add IF NOT EXISTS condition
319
	 * @param	array	$attributes	Associative array of table attributes
320
	 * @return	bool
321
	 */
322
	public function create_table($table, $if_not_exists = FALSE, array $attributes = array())
323
	{
324
		if ($table === '')
325
		{
326
			show_error('A table name is required for that operation.');
0 ignored issues
show
Bug introduced by
The function show_error 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

326
			/** @scrutinizer ignore-call */ 
327
   show_error('A table name is required for that operation.');
Loading history...
327
		}
328
		else
329
		{
330
			$table = $this->db->dbprefix.$table;
331
		}
332
333
		if (count($this->fields) === 0)
334
		{
335
			show_error('Field information is required.');
336
		}
337
338
		$sql = $this->_create_table($table, $if_not_exists, $attributes);
339
340
		if (is_bool($sql))
0 ignored issues
show
introduced by
The condition is_bool($sql) can never be true.
Loading history...
341
		{
342
			$this->_reset();
343
			if ($sql === FALSE)
344
			{
345
				return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
346
			}
347
		}
348
349
		if (($result = $this->db->query($sql)) !== FALSE)
350
		{
351
			isset($this->db->data_cache['table_names']) && $this->db->data_cache['table_names'][] = $table;
352
353
			// Most databases don't support creating indexes from within the CREATE TABLE statement
354
			if ( ! empty($this->keys))
355
			{
356
				for ($i = 0, $sqls = $this->_process_indexes($table), $c = count($sqls); $i < $c; $i++)
357
				{
358
					$this->db->query($sqls[$i]);
359
				}
360
			}
361
		}
362
363
		$this->_reset();
364
		return $result;
365
	}
366
367
	// --------------------------------------------------------------------
368
369
	/**
370
	 * Create Table
371
	 *
372
	 * @param	string	$table		Table name
373
	 * @param	bool	$if_not_exists	Whether to add 'IF NOT EXISTS' condition
374
	 * @param	array	$attributes	Associative array of table attributes
375
	 * @return	mixed
376
	 */
377
	protected function _create_table($table, $if_not_exists, $attributes)
378
	{
379
		if ($if_not_exists === TRUE && $this->_create_table_if === FALSE)
0 ignored issues
show
introduced by
The condition $if_not_exists === TRUE ...eate_table_if === FALSE can never be true.
Loading history...
380
		{
381
			if ($this->db->table_exists($table))
382
			{
383
				return TRUE;
384
			}
385
			else
386
			{
387
				$if_not_exists = FALSE;
388
			}
389
		}
390
391
		$sql = ($if_not_exists)
392
			? sprintf($this->_create_table_if, $this->db->escape_identifiers($table))
393
			: 'CREATE TABLE';
394
395
		$columns = $this->_process_fields(TRUE);
396
		for ($i = 0, $c = count($columns); $i < $c; $i++)
397
		{
398
			$columns[$i] = ($columns[$i]['_literal'] !== FALSE)
399
					? "\n\t".$columns[$i]['_literal']
400
					: "\n\t".$this->_process_column($columns[$i]);
401
		}
402
403
		$columns = implode(',', $columns)
404
				.$this->_process_primary_keys($table);
405
406
		// Are indexes created from within the CREATE TABLE statement? (e.g. in MySQL)
407
		if ($this->_create_table_keys === TRUE)
408
		{
409
			$columns .= $this->_process_indexes($table);
410
		}
411
412
		// _create_table will usually have the following format: "%s %s (%s\n)"
413
		$sql = sprintf($this->_create_table.'%s',
414
			$sql,
415
			$this->db->escape_identifiers($table),
416
			$columns,
417
			$this->_create_table_attr($attributes)
418
		);
419
420
		return $sql;
421
	}
422
423
	// --------------------------------------------------------------------
424
425
	/**
426
	 * CREATE TABLE attributes
427
	 *
428
	 * @param	array	$attributes	Associative array of table attributes
429
	 * @return	string
430
	 */
431
	protected function _create_table_attr($attributes)
432
	{
433
		$sql = '';
434
435
		foreach (array_keys($attributes) as $key)
436
		{
437
			if (is_string($key))
438
			{
439
				$sql .= ' '.strtoupper($key).' '.$attributes[$key];
440
			}
441
		}
442
443
		return $sql;
444
	}
445
446
	// --------------------------------------------------------------------
447
448
	/**
449
	 * Drop Table
450
	 *
451
	 * @param	string	$table_name	Table name
452
	 * @param	bool	$if_exists	Whether to add an IF EXISTS condition
453
	 * @return	bool
454
	 */
455
	public function drop_table($table_name, $if_exists = FALSE)
456
	{
457
		if ($table_name === '')
458
		{
459
			return ($this->db->db_debug) ? $this->db->display_error('db_table_name_required') : FALSE;
460
		}
461
462
		if (($query = $this->_drop_table($this->db->dbprefix.$table_name, $if_exists)) === TRUE)
0 ignored issues
show
introduced by
The condition $query = $this->_drop_ta...e, $if_exists) === TRUE can never be true.
Loading history...
463
		{
464
			return TRUE;
465
		}
466
467
		$query = $this->db->query($query);
468
469
		// Update table list cache
470
		if ($query && ! empty($this->db->data_cache['table_names']))
471
		{
472
			$key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
473
			if ($key !== FALSE)
474
			{
475
				unset($this->db->data_cache['table_names'][$key]);
476
			}
477
		}
478
479
		return $query;
480
	}
481
482
	// --------------------------------------------------------------------
483
484
	/**
485
	 * Drop Table
486
	 *
487
	 * Generates a platform-specific DROP TABLE string
488
	 *
489
	 * @param	string	$table		Table name
490
	 * @param	bool	$if_exists	Whether to add an IF EXISTS condition
491
	 * @return	mixed	(Returns a platform-specific DROP table string, or TRUE to indicate there's nothing to do)
492
	 */
493
	protected function _drop_table($table, $if_exists)
494
	{
495
		$sql = 'DROP TABLE';
496
497
		if ($if_exists)
498
		{
499
			if ($this->_drop_table_if === FALSE)
0 ignored issues
show
introduced by
The condition $this->_drop_table_if === FALSE can never be true.
Loading history...
500
			{
501
				if ( ! $this->db->table_exists($table))
502
				{
503
					return TRUE;
504
				}
505
			}
506
			else
507
			{
508
				$sql = sprintf($this->_drop_table_if, $this->db->escape_identifiers($table));
509
			}
510
		}
511
512
		return $sql.' '.$this->db->escape_identifiers($table);
513
	}
514
515
	// --------------------------------------------------------------------
516
517
	/**
518
	 * Rename Table
519
	 *
520
	 * @param	string	$table_name	Old table name
521
	 * @param	string	$new_table_name	New table name
522
	 * @return	bool
523
	 */
524
	public function rename_table($table_name, $new_table_name)
525
	{
526
		if ($table_name === '' OR $new_table_name === '')
527
		{
528
			show_error('A table name is required for that operation.');
0 ignored issues
show
Bug introduced by
The function show_error 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

528
			/** @scrutinizer ignore-call */ 
529
   show_error('A table name is required for that operation.');
Loading history...
529
			return FALSE;
530
		}
531
		elseif ($this->_rename_table === FALSE)
0 ignored issues
show
introduced by
The condition $this->_rename_table === FALSE can never be true.
Loading history...
532
		{
533
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
534
		}
535
536
		$result = $this->db->query(sprintf($this->_rename_table,
537
						$this->db->escape_identifiers($this->db->dbprefix.$table_name),
538
						$this->db->escape_identifiers($this->db->dbprefix.$new_table_name))
539
					);
540
541
		if ($result && ! empty($this->db->data_cache['table_names']))
542
		{
543
			$key = array_search(strtolower($this->db->dbprefix.$table_name), array_map('strtolower', $this->db->data_cache['table_names']), TRUE);
544
			if ($key !== FALSE)
545
			{
546
				$this->db->data_cache['table_names'][$key] = $this->db->dbprefix.$new_table_name;
547
			}
548
		}
549
550
		return $result;
551
	}
552
553
	// --------------------------------------------------------------------
554
555
	/**
556
	 * Column Add
557
	 *
558
	 * @todo	Remove deprecated $_after option in 3.1+
559
	 * @param	string	$table	Table name
560
	 * @param	array	$field	Column definition
561
	 * @param	string	$_after	Column for AFTER clause (deprecated)
562
	 * @return	bool
563
	 */
564
	public function add_column($table, $field, $_after = NULL)
565
	{
566
		// Work-around for literal column definitions
567
		is_array($field) OR $field = array($field);
568
569
		foreach (array_keys($field) as $k)
570
		{
571
			// Backwards-compatibility work-around for MySQL/CUBRID AFTER clause (remove in 3.1+)
572
			if ($_after !== NULL && is_array($field[$k]) && ! isset($field[$k]['after']))
573
			{
574
				$field[$k]['after'] = $_after;
575
			}
576
577
			$this->add_field(array($k => $field[$k]));
578
		}
579
580
		$sqls = $this->_alter_table('ADD', $this->db->dbprefix.$table, $this->_process_fields());
581
		$this->_reset();
582
		if ($sqls === FALSE)
0 ignored issues
show
introduced by
The condition $sqls === FALSE can never be true.
Loading history...
583
		{
584
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
585
		}
586
587
		for ($i = 0, $c = count($sqls); $i < $c; $i++)
0 ignored issues
show
Bug introduced by
It seems like $sqls can also be of type string; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

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

587
		for ($i = 0, $c = count(/** @scrutinizer ignore-type */ $sqls); $i < $c; $i++)
Loading history...
588
		{
589
			if ($this->db->query($sqls[$i]) === FALSE)
590
			{
591
				return FALSE;
592
			}
593
		}
594
595
		return TRUE;
596
	}
597
598
	// --------------------------------------------------------------------
599
600
	/**
601
	 * Column Drop
602
	 *
603
	 * @param	string	$table		Table name
604
	 * @param	string	$column_name	Column name
605
	 * @return	bool
606
	 */
607
	public function drop_column($table, $column_name)
608
	{
609
		$sql = $this->_alter_table('DROP', $this->db->dbprefix.$table, $column_name);
610
		if ($sql === FALSE)
0 ignored issues
show
introduced by
The condition $sql === FALSE can never be true.
Loading history...
611
		{
612
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
613
		}
614
615
		return $this->db->query($sql);
616
	}
617
618
	// --------------------------------------------------------------------
619
620
	/**
621
	 * Column Modify
622
	 *
623
	 * @param	string	$table	Table name
624
	 * @param	string	$field	Column definition
625
	 * @return	bool
626
	 */
627
	public function modify_column($table, $field)
628
	{
629
		// Work-around for literal column definitions
630
		is_array($field) OR $field = array($field);
631
632
		foreach (array_keys($field) as $k)
633
		{
634
			$this->add_field(array($k => $field[$k]));
635
		}
636
637
		if (count($this->fields) === 0)
638
		{
639
			show_error('Field information is required.');
0 ignored issues
show
Bug introduced by
The function show_error 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

639
			/** @scrutinizer ignore-call */ 
640
   show_error('Field information is required.');
Loading history...
640
		}
641
642
		$sqls = $this->_alter_table('CHANGE', $this->db->dbprefix.$table, $this->_process_fields());
643
		$this->_reset();
644
		if ($sqls === FALSE)
0 ignored issues
show
introduced by
The condition $sqls === FALSE can never be true.
Loading history...
645
		{
646
			return ($this->db->db_debug) ? $this->db->display_error('db_unsupported_feature') : FALSE;
647
		}
648
649
		for ($i = 0, $c = count($sqls); $i < $c; $i++)
0 ignored issues
show
Bug introduced by
It seems like $sqls can also be of type string; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

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

649
		for ($i = 0, $c = count(/** @scrutinizer ignore-type */ $sqls); $i < $c; $i++)
Loading history...
650
		{
651
			if ($this->db->query($sqls[$i]) === FALSE)
652
			{
653
				return FALSE;
654
			}
655
		}
656
657
		return TRUE;
658
	}
659
660
	// --------------------------------------------------------------------
661
662
	/**
663
	 * ALTER TABLE
664
	 *
665
	 * @param	string	$alter_type	ALTER type
666
	 * @param	string	$table		Table name
667
	 * @param	mixed	$field		Column definition
668
	 * @return	string|string[]
669
	 */
670
	protected function _alter_table($alter_type, $table, $field)
671
	{
672
		$sql = 'ALTER TABLE '.$this->db->escape_identifiers($table).' ';
673
674
		// DROP has everything it needs now.
675
		if ($alter_type === 'DROP')
676
		{
677
			return $sql.'DROP COLUMN '.$this->db->escape_identifiers($field);
678
		}
679
680
		$sql .= ($alter_type === 'ADD')
681
			? 'ADD '
682
			: $alter_type.' COLUMN ';
683
684
		$sqls = array();
685
		for ($i = 0, $c = count($field); $i < $c; $i++)
686
		{
687
			$sqls[] = $sql
688
				.($field[$i]['_literal'] !== FALSE ? $field[$i]['_literal'] : $this->_process_column($field[$i]));
689
		}
690
691
		return $sqls;
692
	}
693
694
	// --------------------------------------------------------------------
695
696
	/**
697
	 * Process fields
698
	 *
699
	 * @param	bool	$create_table
700
	 * @return	array
701
	 */
702
	protected function _process_fields($create_table = FALSE)
703
	{
704
		$fields = array();
705
706
		foreach ($this->fields as $key => $attributes)
707
		{
708
			if (is_int($key) && ! is_array($attributes))
709
			{
710
				$fields[] = array('_literal' => $attributes);
711
				continue;
712
			}
713
714
			$attributes = array_change_key_case($attributes, CASE_UPPER);
715
716
			if ($create_table === TRUE && empty($attributes['TYPE']))
717
			{
718
				continue;
719
			}
720
721
			isset($attributes['TYPE']) && $this->_attr_type($attributes);
722
723
			$field = array(
724
				'name'			=> $key,
725
				'new_name'		=> isset($attributes['NAME']) ? $attributes['NAME'] : NULL,
726
				'type'			=> isset($attributes['TYPE']) ? $attributes['TYPE'] : NULL,
727
				'length'		=> '',
728
				'unsigned'		=> '',
729
				'null'			=> '',
730
				'unique'		=> '',
731
				'default'		=> '',
732
				'auto_increment'	=> '',
733
				'_literal'		=> FALSE
734
			);
735
736
			isset($attributes['TYPE']) && $this->_attr_unsigned($attributes, $field);
737
738
			if ($create_table === FALSE)
739
			{
740
				if (isset($attributes['AFTER']))
741
				{
742
					$field['after'] = $attributes['AFTER'];
743
				}
744
				elseif (isset($attributes['FIRST']))
745
				{
746
					$field['first'] = (bool) $attributes['FIRST'];
747
				}
748
			}
749
750
			$this->_attr_default($attributes, $field);
751
752
			if (isset($attributes['NULL']))
753
			{
754
				if ($attributes['NULL'] === TRUE)
755
				{
756
					$field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
757
				}
758
				else
759
				{
760
					$field['null'] = ' NOT NULL';
761
				}
762
			}
763
			elseif ($create_table === TRUE)
764
			{
765
				$field['null'] = ' NOT NULL';
766
			}
767
768
			$this->_attr_auto_increment($attributes, $field);
769
			$this->_attr_unique($attributes, $field);
770
771
			if (isset($attributes['COMMENT']))
772
			{
773
				$field['comment'] = $this->db->escape($attributes['COMMENT']);
774
			}
775
776
			if (isset($attributes['TYPE']) && ! empty($attributes['CONSTRAINT']))
777
			{
778
				switch (strtoupper($attributes['TYPE']))
779
				{
780
					case 'ENUM':
781
					case 'SET':
782
						$attributes['CONSTRAINT'] = $this->db->escape($attributes['CONSTRAINT']);
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment if this fall-through is intended.
Loading history...
783
					default:
784
						$field['length'] = is_array($attributes['CONSTRAINT'])
785
							? '('.implode(',', $attributes['CONSTRAINT']).')'
786
							: '('.$attributes['CONSTRAINT'].')';
787
						break;
788
				}
789
			}
790
791
			$fields[] = $field;
792
		}
793
794
		return $fields;
795
	}
796
797
	// --------------------------------------------------------------------
798
799
	/**
800
	 * Process column
801
	 *
802
	 * @param	array	$field
803
	 * @return	string
804
	 */
805
	protected function _process_column($field)
806
	{
807
		return $this->db->escape_identifiers($field['name'])
808
			.' '.$field['type'].$field['length']
809
			.$field['unsigned']
810
			.$field['default']
811
			.$field['null']
812
			.$field['auto_increment']
813
			.$field['unique'];
814
	}
815
816
	// --------------------------------------------------------------------
817
818
	/**
819
	 * Field attribute TYPE
820
	 *
821
	 * Performs a data type mapping between different databases.
822
	 *
823
	 * @param	array	&$attributes
824
	 * @return	void
825
	 */
826
	protected function _attr_type(&$attributes)
0 ignored issues
show
Unused Code introduced by
The parameter $attributes is not used and could be removed. ( Ignorable by Annotation )

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

826
	protected function _attr_type(/** @scrutinizer ignore-unused */ &$attributes)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
827
	{
828
		// Usually overridden by drivers
829
	}
830
831
	// --------------------------------------------------------------------
832
833
	/**
834
	 * Field attribute UNSIGNED
835
	 *
836
	 * Depending on the _unsigned property value:
837
	 *
838
	 *	- TRUE will always set $field['unsigned'] to 'UNSIGNED'
839
	 *	- FALSE will always set $field['unsigned'] to ''
840
	 *	- array(TYPE) will set $field['unsigned'] to 'UNSIGNED',
841
	 *		if $attributes['TYPE'] is found in the array
842
	 *	- array(TYPE => UTYPE) will change $field['type'],
843
	 *		from TYPE to UTYPE in case of a match
844
	 *
845
	 * @param	array	&$attributes
846
	 * @param	array	&$field
847
	 * @return	void
848
	 */
849
	protected function _attr_unsigned(&$attributes, &$field)
850
	{
851
		if (empty($attributes['UNSIGNED']) OR $attributes['UNSIGNED'] !== TRUE)
852
		{
853
			return;
854
		}
855
856
		// Reset the attribute in order to avoid issues if we do type conversion
857
		$attributes['UNSIGNED'] = FALSE;
858
859
		if (is_array($this->_unsigned))
860
		{
861
			foreach (array_keys($this->_unsigned) as $key)
862
			{
863
				if (is_int($key) && strcasecmp($attributes['TYPE'], $this->_unsigned[$key]) === 0)
0 ignored issues
show
Bug introduced by
It seems like $attributes['TYPE'] can also be of type false; however, parameter $str1 of strcasecmp() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

863
				if (is_int($key) && strcasecmp(/** @scrutinizer ignore-type */ $attributes['TYPE'], $this->_unsigned[$key]) === 0)
Loading history...
864
				{
865
					$field['unsigned'] = ' UNSIGNED';
866
					return;
867
				}
868
				elseif (is_string($key) && strcasecmp($attributes['TYPE'], $key) === 0)
869
				{
870
					$field['type'] = $key;
871
					return;
872
				}
873
			}
874
875
			return;
876
		}
877
878
		$field['unsigned'] = ($this->_unsigned === TRUE) ? ' UNSIGNED' : '';
879
	}
880
881
	// --------------------------------------------------------------------
882
883
	/**
884
	 * Field attribute DEFAULT
885
	 *
886
	 * @param	array	&$attributes
887
	 * @param	array	&$field
888
	 * @return	void
889
	 */
890
	protected function _attr_default(&$attributes, &$field)
891
	{
892
		if ($this->_default === FALSE)
0 ignored issues
show
introduced by
The condition $this->_default === FALSE can never be true.
Loading history...
893
		{
894
			return;
895
		}
896
897
		if (array_key_exists('DEFAULT', $attributes))
898
		{
899
			if ($attributes['DEFAULT'] === NULL)
900
			{
901
				$field['default'] = empty($this->_null) ? '' : $this->_default.$this->_null;
902
903
				// Override the NULL attribute if that's our default
904
				$attributes['NULL'] = TRUE;
905
				$field['null'] = empty($this->_null) ? '' : ' '.$this->_null;
906
			}
907
			else
908
			{
909
				$field['default'] = $this->_default.$this->db->escape($attributes['DEFAULT']);
910
			}
911
		}
912
	}
913
914
	// --------------------------------------------------------------------
915
916
	/**
917
	 * Field attribute UNIQUE
918
	 *
919
	 * @param	array	&$attributes
920
	 * @param	array	&$field
921
	 * @return	void
922
	 */
923
	protected function _attr_unique(&$attributes, &$field)
924
	{
925
		if ( ! empty($attributes['UNIQUE']) && $attributes['UNIQUE'] === TRUE)
926
		{
927
			$field['unique'] = ' UNIQUE';
928
		}
929
	}
930
931
	// --------------------------------------------------------------------
932
933
	/**
934
	 * Field attribute AUTO_INCREMENT
935
	 *
936
	 * @param	array	&$attributes
937
	 * @param	array	&$field
938
	 * @return	void
939
	 */
940
	protected function _attr_auto_increment(&$attributes, &$field)
941
	{
942
		if ( ! empty($attributes['AUTO_INCREMENT']) && $attributes['AUTO_INCREMENT'] === TRUE && stripos($field['type'], 'int') !== FALSE)
943
		{
944
			$field['auto_increment'] = ' AUTO_INCREMENT';
945
		}
946
	}
947
948
	// --------------------------------------------------------------------
949
950
	/**
951
	 * Process primary keys
952
	 *
953
	 * @param	string	$table	Table name
954
	 * @return	string
955
	 */
956
	protected function _process_primary_keys($table)
957
	{
958
		$sql = '';
959
960
		for ($i = 0, $c = count($this->primary_keys); $i < $c; $i++)
961
		{
962
			if ( ! isset($this->fields[$this->primary_keys[$i]]))
963
			{
964
				unset($this->primary_keys[$i]);
965
			}
966
		}
967
968
		if (count($this->primary_keys) > 0)
969
		{
970
			$sql .= ",\n\tCONSTRAINT ".$this->db->escape_identifiers('pk_'.$table)
971
				.' PRIMARY KEY('.implode(', ', $this->db->escape_identifiers($this->primary_keys)).')';
972
		}
973
974
		return $sql;
975
	}
976
977
	// --------------------------------------------------------------------
978
979
	/**
980
	 * Process indexes
981
	 *
982
	 * @param	string	$table	Table name
983
	 * @return	string[] list of SQL statements
984
	 */
985
	protected function _process_indexes($table)
986
	{
987
		$sqls = array();
988
989
		for ($i = 0, $c = count($this->keys); $i < $c; $i++)
990
		{
991
			if (is_array($this->keys[$i]))
992
			{
993
				for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++)
994
				{
995
					if ( ! isset($this->fields[$this->keys[$i][$i2]]))
996
					{
997
						unset($this->keys[$i][$i2]);
998
						continue;
999
					}
1000
				}
1001
			}
1002
			elseif ( ! isset($this->fields[$this->keys[$i]]))
1003
			{
1004
				unset($this->keys[$i]);
1005
				continue;
1006
			}
1007
1008
			is_array($this->keys[$i]) OR $this->keys[$i] = array($this->keys[$i]);
1009
1010
			$sqls[] = 'CREATE INDEX '.$this->db->escape_identifiers($table.'_'.implode('_', $this->keys[$i]))
1011
				.' ON '.$this->db->escape_identifiers($table)
1012
				.' ('.implode(', ', $this->db->escape_identifiers($this->keys[$i])).');';
1013
		}
1014
1015
		return $sqls;
1016
	}
1017
1018
	// --------------------------------------------------------------------
1019
1020
	/**
1021
	 * Reset
1022
	 *
1023
	 * Resets table creation vars
1024
	 *
1025
	 * @return	void
1026
	 */
1027
	protected function _reset()
1028
	{
1029
		$this->fields = $this->keys = $this->primary_keys = array();
1030
	}
1031
1032
}
1033