
This article is devoted to the practical use of the
Migraton library, which appeared in the update CodeIgniter version 2.1.0. We strongly recommend that you read the
first part of the article , which deals directly with the creation of migrations, before reading this material.
Problem Statement and Solution
To begin with, we will agree that the application should be updated via the admin interface only by login, and before that, respectively, 503 responses will be sent to requests for any of the pages.
Intermediate versions, like kickbacks, are not needed yet, so the site will be updated immediately to the latest version.Add an alert to visitors
In the project for which I did the integration of migrations, all controllers also inherit not the basic
CI_Controller , but the extended
MY_Controller , which contains in its constructor some utility actions, including with the database. Therefore, for the
% site_path% / application / core / MY_Controller.php file, we will need to add a few lines:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); class MY_Controller extends CI_Controller { protected $db_update = FALSE;
Note: as in the previous article, all source code files are listed at the end of the article.')
I think that the code as a whole is understandable, we need only note that we will show the error everywhere except the admin page (the
Admin controller, which inherits
MY_Controller ). But for the admin we will not perform the constructor further, because it may contain references to a database that has an outdated structure. By the way, as you can see, first in the constructor, the code of the parent constructor is invoked, which implements the
Decorator pattern.
Create an update script through admin panel
In my case, the entire admin panel was in the same
Admin controller, so we take the same case for the sake of simplicity.
This admin controller contains several diverse methods that allow you to manage the content of the site. Not a very good and elegant solution, to be honest - I still strongly advise you to distribute it to different controllers or even use the
HMVC plugin for CodeIgniter (on the habr was already a
good example of its use).
So, we have a task to make sure that you can log in to the admin panel, and on any of the pages you are prompted to update the database. For this, the magic
_remap method will be
perfect , which will be called when accessing any of the controller methods, and make a decision, transfer control to the requested method or
show the cookie to do some other action:
public function _remap($method, $params = array()) { if (!$this->m_user->authorised() && $method != 'index') { header('Location:/admin/');
It is worth
explaining here that
m_user is a model that contains all the methods for working with admin users (I suggest you implement it yourself), the
index method can show the login form for logged-in users, well,
logout is understandable what it does.
In addition, we will create a method for updating the database there:
public function update_db() { $this->data['body'] = '<h1> </h1>'; if ( ! $this->migration->current()) { show_error($this->migration->error_string()); } $this->load->view('admin/default.phtml', $this->data); }
Rule config and test
Finally, it remains to correct the config, and we will be able to use all that we have written for our project. To do this, add the
Migration class to the autoload. Now the line with auto initialization of libraries in my case looks like this (
%% site_path% / application / config / autoload.php file ):
$autoload['libraries'] = array('database', 'session', 'migration');
We also need to check in the
% site_path% / application / config / migration.php file whether migrations are enabled, whether the path and the version of the database required for our code to work correctly are specified (everything is the same as in the
past article ):
$config['migration_enabled'] = TRUE; $config['migration_version'] = 1; $config['migration_path'] = APPPATH . 'migrations/';
Please note that I have specified the 1st version, which implies that we have already done the mailing list functionality, the migration for which we wrote in the
previous tutorial .
Now you can go to any page of your site that is not related to the admin panel and you will need to see an error message, because we now have a
zero version of the database (at the first initialization, the
Migration library created a migrations label in your database and indicated version 0 there), and the code version in the config is the
first one . Going to the admin area and having passed the authorization, you will see a suggestion to update the database, and clicking on the link will get a fresh application, without the need to perform all requests manually!
Bonus - update script via CLI
As a bonus, consider creating a script for updating via
cli , which will allow us to automate migrations when uploading them to the site, for example, from version control systems using hooks.
Fortunately, CodeIgniter in its latest versions has the ability to run from the command line, which is called out of the box. Therefore, to begin with, we will create a
% site_path% / application / controllers / cli.php controller with a private variable
$ args , which will contain all the arguments with which the script was called, except for the name of the controller and its method (we cut them off in the constructor):
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); class Cli extends MY_Controller { private $args = array();
By the way, I advise you also to pay attention to the place in the constructor, where it is checked whether the request came through the CLI. We do not want to be able to perform service methods through the site! As you can see, I also disabled the profiler here, because on test servers, it is on by default everywhere, and in the CLI it would clearly be superfluous.
Finally, write a method for migrations:
public function migration() { if ( !is_array($this->args) || empty($this->args)) { print ( "Usage: php index.php cli migration [OPTIONS]\n\n" ); print ( "Options are:\n" ); print ( "-l, --last\t\tupdate database to the latest version\n" ); print ( "-c, --current\t\t show current versions of database and code\n" ); exit; } for ( $i=0; $i<count($this->args); $i++ ) { $arg = $this->args[$i]; if ( $arg=="-l" || $arg=="--last" ) { print "Updating your database to the latest version..\n"; if (!$this->migration->current()) { print $this->migration->error_string().'\n'; exit; } else print "Update complete!\n"; } elseif ( $arg=="-c" || $arg=="--current" ) { print 'Current code version is:\t'. $this->migration->get_fs_version().'\n'; print 'Current database version is:\t'.$this->migration->get_db_version().'\n'; } } }
To call it, you only need to type in the command line "
php /%index_dir%/index.php cli migration " with no additional attributes, and the script will kindly prompt you for the options available for use. Well, if you type "
php /%index_dir%/index.php cli migration -l ", the method will try to update your database and give you the result.
Of course, this piece of code is just an example, which performs only the basics themselves, but it gives you a general idea of using CLI and migrations, and it’s not difficult for you to add, for example, the '-r' option for updating the database to the specified revision (which by the way will be a simple homework for you).
Conclusion
Now we have, albeit a simple, but well-established database update mechanism integrated into our project, which among other things is able to warn users about the current update. You must admit that this is better than if they saw the bugs related to the inconsistency of the versions of the database and the code, or some other indecency. In addition, we can now add a hook to our favorite version control system that will automatically update the database when uploading a new version of the site.
Download full source archivePart One: Database Migrations - Library Overview and Usage