/lenasys/trunk

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/lenasys/trunk
20.1.1 by galaxyAbstractor
* Added an simple admin panel to the codeviewer-cmssy stuff
1
<?php defined('BASEPATH') OR exit('No direct script access allowed');
2
/**
3
 * CodeIgniter
4
 *
5
 * An open source application development framework for PHP 5.1.6 or newer
6
 *
7
 * @package		CodeIgniter
8
 * @author		EllisLab Dev Team
9
 * @copyright	Copyright (c) 2006 - 2012, EllisLab, Inc.
10
 * @license		http://codeigniter.com/user_guide/license.html
11
 * @link		http://codeigniter.com
12
 * @since		Version 1.0
13
 * @filesource
14
 */
15
16
// ------------------------------------------------------------------------
17
18
/**
19
 * Migration Class
20
 *
21
 * All migrations should implement this, forces up() and down() and gives
22
 * access to the CI super-global.
23
 *
24
 * @package		CodeIgniter
25
 * @subpackage	Libraries
26
 * @category	Libraries
27
 * @author		Reactor Engineers
28
 * @link
29
 */
30
class CI_Migration {
31
32
	protected $_migration_enabled = FALSE;
33
	protected $_migration_path = NULL;
34
	protected $_migration_version = 0;
35
36
	protected $_error_string = '';
37
38
	public function __construct($config = array())
39
	{
40
		# Only run this constructor on main library load
41
		if (get_parent_class($this) !== FALSE)
42
		{
43
			return;
44
		}
45
46
		foreach ($config as $key => $val)
47
		{
48
			$this->{'_' . $key} = $val;
49
		}
50
51
		log_message('debug', 'Migrations class initialized');
52
53
		// Are they trying to use migrations while it is disabled?
54
		if ($this->_migration_enabled !== TRUE)
55
		{
56
			show_error('Migrations has been loaded but is disabled or set up incorrectly.');
57
		}
58
59
		// If not set, set it
60
		$this->_migration_path == '' AND $this->_migration_path = APPPATH . 'migrations/';
61
62
		// Add trailing slash if not set
63
		$this->_migration_path = rtrim($this->_migration_path, '/').'/';
64
65
		// Load migration language
66
		$this->lang->load('migration');
67
68
		// They'll probably be using dbforge
69
		$this->load->dbforge();
70
71
		// If the migrations table is missing, make it
72
		if ( ! $this->db->table_exists('migrations'))
73
		{
74
			$this->dbforge->add_field(array(
75
				'version' => array('type' => 'INT', 'constraint' => 3),
76
			));
77
78
			$this->dbforge->create_table('migrations', TRUE);
79
80
			$this->db->insert('migrations', array('version' => 0));
81
		}
82
	}
83
84
	// --------------------------------------------------------------------
85
86
	/**
87
	 * Migrate to a schema version
88
	 *
89
	 * Calls each migration step required to get to the schema version of
90
	 * choice
91
	 *
92
	 * @param	int	Target schema version
93
	 * @return	mixed	TRUE if already latest, FALSE if failed, int if upgraded
94
	 */
95
	public function version($target_version)
96
	{
97
		$start = $current_version = $this->_get_version();
98
		$stop = $target_version;
99
100
		if ($target_version > $current_version)
101
		{
102
			// Moving Up
103
			++$start;
104
			++$stop;
105
			$step = 1;
106
		}
107
		else
108
		{
109
			// Moving Down
110
			$step = -1;
111
		}
112
113
		$method = ($step === 1) ? 'up' : 'down';
114
		$migrations = array();
115
116
		// We now prepare to actually DO the migrations
117
		// But first let's make sure that everything is the way it should be
118
		for ($i = $start; $i != $stop; $i += $step)
119
		{
120
			$f = glob(sprintf($this->_migration_path . '%03d_*.php', $i));
121
122
			// Only one migration per step is permitted
123
			if (count($f) > 1)
124
			{
125
				$this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $i);
126
				return FALSE;
127
			}
128
129
			// Migration step not found
130
			if (count($f) == 0)
131
			{
132
				// If trying to migrate up to a version greater than the last
133
				// existing one, migrate to the last one.
134
				if ($step == 1)
135
				{
136
					break;
137
				}
138
139
				// If trying to migrate down but we're missing a step,
140
				// something must definitely be wrong.
141
				$this->_error_string = sprintf($this->lang->line('migration_not_found'), $i);
142
				return FALSE;
143
			}
144
145
			$file = basename($f[0]);
146
			$name = basename($f[0], '.php');
147
148
			// Filename validations
149
			if (preg_match('/^\d{3}_(\w+)$/', $name, $match))
150
			{
151
				$match[1] = strtolower($match[1]);
152
153
				// Cannot repeat a migration at different steps
154
				if (in_array($match[1], $migrations))
155
				{
156
					$this->_error_string = sprintf($this->lang->line('migration_multiple_version'), $match[1]);
157
					return FALSE;
158
				}
159
160
				include $f[0];
161
				$class = 'Migration_' . ucfirst($match[1]);
162
163
				if ( ! class_exists($class))
164
				{
165
					$this->_error_string = sprintf($this->lang->line('migration_class_doesnt_exist'), $class);
166
					return FALSE;
167
				}
168
169
				if ( ! is_callable(array($class, $method)))
170
				{
171
					$this->_error_string = sprintf($this->lang->line('migration_missing_'.$method.'_method'), $class);
172
					return FALSE;
173
				}
174
175
				$migrations[] = $match[1];
176
			}
177
			else
178
			{
179
				$this->_error_string = sprintf($this->lang->line('migration_invalid_filename'), $file);
180
				return FALSE;
181
			}
182
		}
183
184
		log_message('debug', 'Current migration: ' . $current_version);
185
186
		$version = $i + ($step == 1 ? -1 : 0);
187
188
		// If there is nothing to do so quit
189
		if ($migrations === array())
190
		{
191
			return TRUE;
192
		}
193
194
		log_message('debug', 'Migrating from ' . $method . ' to version ' . $version);
195
196
		// Loop through the migrations
197
		foreach ($migrations AS $migration)
198
		{
199
			// Run the migration class
200
			$class = 'Migration_' . ucfirst(strtolower($migration));
201
			call_user_func(array(new $class, $method));
202
203
			$current_version += $step;
204
			$this->_update_version($current_version);
205
		}
206
207
		log_message('debug', 'Finished migrating to '.$current_version);
208
209
		return $current_version;
210
	}
211
212
	// --------------------------------------------------------------------
213
214
	/**
215
	 * Set's the schema to the latest migration
216
	 *
217
	 * @return	mixed	true if already latest, false if failed, int if upgraded
218
	 */
219
	public function latest()
220
	{
221
		if ( ! $migrations = $this->find_migrations())
222
		{
223
			$this->_error_string = $this->line->lang('migration_none_found');
224
			return false;
225
		}
226
227
		$last_migration = basename(end($migrations));
228
229
		// Calculate the last migration step from existing migration
230
		// filenames and procceed to the standard version migration
231
		return $this->version((int) substr($last_migration, 0, 3));
232
	}
233
234
	// --------------------------------------------------------------------
235
236
	/**
237
	 * Set's the schema to the migration version set in config
238
	 *
239
	 * @return	mixed	true if already current, false if failed, int if upgraded
240
	 */
241
	public function current()
242
	{
243
		return $this->version($this->_migration_version);
244
	}
245
246
	// --------------------------------------------------------------------
247
248
	/**
249
	 * Error string
250
	 *
251
	 * @return	string	Error message returned as a string
252
	 */
253
	public function error_string()
254
	{
255
		return $this->_error_string;
256
	}
257
258
	// --------------------------------------------------------------------
259
260
	/**
261
	 * Set's the schema to the latest migration
262
	 *
263
	 * @return	mixed	true if already latest, false if failed, int if upgraded
264
	 */
265
	protected function find_migrations()
266
	{
267
		// Load all *_*.php files in the migrations path
268
		$files = glob($this->_migration_path . '*_*.php');
269
		$file_count = count($files);
270
271
		for ($i = 0; $i < $file_count; $i++)
272
		{
273
			// Mark wrongly formatted files as false for later filtering
274
			$name = basename($files[$i], '.php');
275
			if ( ! preg_match('/^\d{3}_(\w+)$/', $name))
276
			{
277
				$files[$i] = FALSE;
278
			}
279
		}
280
281
		sort($files);
282
		return $files;
283
	}
284
285
	// --------------------------------------------------------------------
286
287
	/**
288
	 * Retrieves current schema version
289
	 *
290
	 * @return	int	Current Migration
291
	 */
292
	protected function _get_version()
293
	{
294
		$row = $this->db->get('migrations')->row();
295
		return $row ? $row->version : 0;
296
	}
297
298
	// --------------------------------------------------------------------
299
300
	/**
301
	 * Stores the current schema version
302
	 *
303
	 * @param	int	Migration reached
304
	 * @return	bool
305
	 */
306
	protected function _update_version($migrations)
307
	{
308
		return $this->db->update('migrations', array(
309
			'version' => $migrations
310
		));
311
	}
312
313
	// --------------------------------------------------------------------
314
315
	/**
316
	 * Enable the use of CI super-global
317
	 *
318
	 * @param	mixed	$var
319
	 * @return	mixed
320
	 */
321
	public function __get($var)
322
	{
323
		return get_instance()->$var;
324
	}
325
}
326
327
/* End of file Migration.php */
328
/* Location: ./system/libraries/Migration.php */