osmosis / branches / master / controllers / installer_controller.php

history
<?php
/* SVN FILE: $Id$ */
/**
 * Ósmosis LMS: <http://www.osmosislms.org/>
 * Copyright 2008, Ósmosis LMS
 *
 * This file is part of Ósmosis LMS.
 * Ósmosis LMS is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Ósmosis LMS is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Ósmosis LMS.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @filesource
 * @copyright		Copyright 2008, Ósmosis LMS
 * @link			http://www.osmosislms.org/
 * @package			org.osmosislms
 * @subpackage		org.osmosislms.app
 * @since			Version 2.0 
 * @version			$Revision$
 * @modifiedby		$LastChangedBy$
 * @lastmodified	$Date$
 * @license			http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
 */
App::import('core', 'ConnectionManager');
class InstallerController extends Controller {
	var $uses = null;
    var $components = null;
	var $config_file_location;
	var $helpers = array('Javascript', 'Html', 'Form');
	var $current_step;
	var $current_step_position = 0;
	var $current_step_name;
	var $valid_steps;
	
	function beforeFilter() {
		$this->valid_steps = array(
			'database_info'		=> __('Database Info', true),
			'load_database'		=> false,
			'configure_mailing' => __('Configure Mailing', true),
			'init_acl'			=> __('Done!', true)
		);
		$this->config_file_location = CONFIGS . 'database.php';
		$this->components = array('Session');
		App::import('Component','Session');
		$this->Session = new SessionComponent();
	}
	
	/**
	 * Dispatcher function that calls the actual step action.
	 *
	 * @param string $step step name
	 * @return void
	 */
	function index($step = 'start') {
		$steps = array_keys($this->valid_steps);
		if (!in_array($step, $steps)) {
			$this->redirect(array('action' => 'index', $steps[0]));
		}
		foreach ($steps as $pos => $_step) {
			if ($_step == $step) {
				$this->current_step_position = $pos;
				$this->current_step_name = $this->valid_steps[$_step];
				break;
			}
		}
		if ($step != $steps[0] && !file_exists($this->config_file_location)) {
			$this->Session->setFlash(
				__('Database configuration file not found.',true),
				'default', array('class' => 'error')
			);
			$this->redirect(array('action' => 'index'));
		}
		$this->current_step = $step;
		$this->set('current_step_name', $this->current_step_name);
		$this->set('current_step', $this->current_step);
		$this->set('current_step_position', $this->current_step_position+1);
		$this->{$step}();
		$this->render($step, 'install');
	}
	
	/**
	 * First step in the installation process. Allows the user to create the database.php file.
	 * Handles only MySQL (tested) and PostgreSQL (not tested).
	 *
	 * @return void
	 */	
	function database_info() {
		if (!empty($this->data)) {
			@$db = &ConnectionManager::create('default',
				array(
					'driver'		=> $this->data['Installer']['driver'],
					'persistent'	=> false,
					'host'			=> $this->data['Installer']['host'],
					'port'			=> $this->data['Installer']['port'],
					'login'			=> $this->data['Installer']['dbusername'],
					'password'		=> $this->data['Installer']['dbpassword'],
					'database'		=> $this->data['Installer']['name'],
					'schema'		=> '',
					'prefix'		=>  $this->data['Installer']['prefix'],   
					'encoding'		=> 'UTF-8'
				)
			);
			if ($db->connected) {
				$config = $this->__createDatabaseConfiguration($db->config);
				if (file_exists($this->config_file_location)) {
					$this->__step();
				} else {
					$this->Session->setFlash(
						__('Database configuration file not writable.',true),
						'default', array('class' => 'error')
					);
					$this->set('dbFileNotWritable', $config);
					$this->set('dbConfigFile', $this->config_file_location);
				}
			} else {
				$this->Session->setFlash(
					__('Could not connect to the database with the given configuration', true),
					'default', array('class' => 'error')
				);
			}
		} else {
			$this->data['Installer']['host'] = 'localhost';
		}
		$configFileExists = file_exists($this->config_file_location);
		$drivers =	array(
			'mysql' => 'MySQL',
			'postgres' => 'PostgreSQL'
		);
		$this->set(compact('drivers', 'configFileExists'));
	}
	
	/**
	 * Second step in the installation process. Creates loads Ósmosis tables into the database.
	 *
	 * @return void
	 */
	function load_database() {
		$db = ConnectionManager::getDataSource('default');
		if (strpos($db->config['driver'], 'mysql') !== false) {
			$db->execute('ALTER DATABASE ' . $db->startQuote . $db->config['database'] . $db->endQuote . ' CHARACTER SET utf8 COLLATE utf8_unicode_ci');
		}
		App::import('Component', 'Installer');
		$installer = new InstallerComponent();
		$installer->startup($this);
		if (!$installer->createSchema()) {
			$message = __('The user does not have enough privileges over the database', true);
			foreach ($installer->errors as $error_message) {
				if (strstr($error_message, 'already exists')) {
					$message = __('The selected database is not empty. Some tables already exist.', true);
					break;
				}
			}
			$this->Session->setFlash(
				$message,
				'default', array('class' => 'error')
			);
			$this->__step(-1);
		} else {
			$this->__step();
		}
	}

	/**
	 * Third step in the installation process. Creates a new admin user.
	 *
	 * @return void
	 */
	function init_acl() {
		App::import('Component', 'Acl');
		App::import('Component', 'Auth');
		App::import('Component', 'InitAcl');
		App::import('Model', 'Member');
		App::import('Model', 'Role');
		App::import('Model', 'Aro');
		$initAcl = new InitAclComponent();
		$initAcl->Acl = new AclComponent();
		$initAcl->Member = new Member();
		$initAcl->Role = new Role();
		$initAcl->Role->Aro = new Aro();
		$initAcl->Auth = new AuthComponent();
		$public_id = $initAcl->initRole('Public');
		$member_id = $initAcl->initRole('Member', $public_id);
		$attendee_id = $initAcl->initRole('Attendee', $member_id);
		$helper_id = $initAcl->initRole('Assistant', $attendee_id);
		$professor_id = $initAcl->initRole('Professor', $helper_id);
		$creator_id = $initAcl->initRole('Owner', $professor_id);
		$member = array('Member' => 
			array(
				'institution_id'=> '00-00000',
				'full_name'	=> 'Administrator',
				'email'		=> 'admin@root.com',
				'phone'		=> '000000000',
				'country'	=> 'Venezuela',
				'city'		=> 'Caracas',
				'sex'		=> 'M',
				'username'	=> 'admin',
				'password'	=> 'admin',
				'password_confirm'	=> 'admin',
				'admin'		=> 1
    		)
		);
		$member_id = $initAcl->initMember($member);
		$initAcl->loadPermissions();
		$this->set(compact('member'));
	}
	
	/**
	 * This step asks the information necesary to allow Ósmosis send emails.
	 *
	 * @return void
	 */	
	function configure_mailing() {
		if (!empty($this->data)) {
			if (!$this->data['Installer']['usesmtp']) {
				unset($this->data['Installer']['smtphost']);
				unset($this->data['Installer']['smtplogin']);
				unset($this->data['Installer']['smtppassword']);
			}
			$configurations = array();
			foreach ($this->data['Installer'] as $key => $value) {
				$value = trim($value);
				if (empty($value)) {
					continue;
				}
				$key = 'Mailer.' . $key;
				$configurations[] = compact('key', 'value');
			}
			App::import('Model', 'Setting');
			$this->Setting = new Setting;
			$this->Setting->deleteAll(array('key' => array_keys($configurations)));
			if ($this->Setting->saveAll($configurations)) {
				$this->__step();
			} else {
				$this->Session->setFlash(
					__('Error saving configurations.',true),
					'default', array('class' => 'error')
				);
			}
		} else {
			$this->data['Installer']['name'] = 'Ósmosis LMS';
			$this->data['Installer']['username'] = 'osmosis';
			$this->data['Installer']['domain'] = $_SERVER['HTTP_HOST'];
			$this->data['Installer']['usesmtp'] = false;
		}
	}
	/**
	 * Helper function that writes the database.php file based on some Datasource configuration array.
	 *
	 * @param array $configs Datasource configuration array
	 * @return string database.php file contents
	 */
	function __createDatabaseConfiguration($configs) {
		unset($configs['connect']);
		unset($configs['schema']);
		$config = 'var $default = ' . var_export($configs, true);
		$config = str_replace("\n", "\n\t", $config);
		$config = "<?php\nclass DATABASE_CONFIG {\n\t$config;\n}\n?>";
		App::import('Core', 'File');
		$config_file = new File($this->config_file_location);
		if (($config_file->exists() && $config_file->writable()) || $config_file->create()) {
			$config_file->write($config);
			$config_file->close();
		}
		return $config;
	}
	
	/**
	 * Redirect to next step or to login page on finish.
	 * This way, step order can be changed in valid_steps array.
	 *
	 * @return void
	 */	
	function __step($direction = +1) {
		$next_position = $this->current_step_position + $direction;
		if ($next_position == count($this->valid_steps)) {
			$this->redirect(array('controller' => 'members', 'action' => 'login'));
		}
		$steps = array_keys($this->valid_steps);
		$this->redirect(array('action' => 'index', $steps[$next_position]));
	}
}
?>