source: pro-bachkim-filespace/sourcecode/system/libraries/Migration.php @ 208

Last change on this file since 208 was 1, checked in by dungnv, 11 years ago
File size: 7.8 KB
Line 
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 */
30class 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->lang->line('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 */
Note: See TracBrowser for help on using the repository browser.