Chamilo is a learning management system focused on ease of use and accessibility
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
chamilo-lms/src/ChamiloLMS/Command/Database/InstallCommand.php

546 lines
18 KiB

<?php
namespace ChamiloLMS\Command\Database;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\AnnotationRegistry;
use Doctrine\DBAL\Migrations\Tools\Console\Command\AbstractCommand;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console;
use Symfony\Component\Yaml\Dumper;
/**
* Class InstallCommand
*/
class InstallCommand extends CommonCommand
{
protected function configure()
{
$this
->setName('chamilo:install')
->setDescription('Execute a Chamilo installation to a specified version')
->addArgument('version', InputArgument::REQUIRED, 'The version to migrate to.', null)
->addOption('path', null, InputOption::VALUE_OPTIONAL, 'The path to the chamilo folder');
}
/**
* Gets the SQL files relation with versions
* @return array
*/
public function getDatabaseMap()
{
$defaultCourseData = array(
array(
'name' => 'course1',
'sql' => array(
'db_course1.sql',
),
),
array(
'name' => 'course2',
'sql' => array(
'db_course2.sql'
)
),
);
return array(
'1.8.7' => array(
'section' => array(
'main' => array(
array(
'name' => 'chamilo',
'sql' => array(
'db_main.sql',
'db_stats.sql',
'db_user.sql'
),
),
),
'course' => $defaultCourseData
),
),
'1.8.8' => array(
'section' => array(
'main' => array(
array(
'name' => 'chamilo',
'sql' => array(
'db_main.sql',
'db_stats.sql',
'db_user.sql'
),
),
),
'course' => $defaultCourseData
),
),
'1.9.0' => array(
'section' => array(
'main' => array(
array(
'name' => 'chamilo',
'sql' => array(
'db_course.sql',
'db_main.sql',
'db_stats.sql',
'db_user.sql'
),
),
),
)
),
'1.10.0' => array(
'section' => array(
'main' => array(
array(
'name' => 'chamilo',
'sql' => array(
'db_course.sql',
'db_main.sql'
),
),
),
)
)
);
}
/**
* Gets the version name folders located in main/install
*
* @return array
*/
public function getAvailableVersions()
{
$installPath = api_get_path(SYS_PATH).'main/install';
$dir = new \DirectoryIterator($installPath);
$dirList = array();
foreach ($dir as $fileInfo) {
if ($fileInfo->isDir() && !$fileInfo->isDot()) {
$dirList[] = $fileInfo->getFilename();
}
}
return $dirList;
}
/**
* Executes a command via CLI
*
* @param Console\Input\InputInterface $input
* @param Console\Output\OutputInterface $output
*
* @return int|null|void
*/
protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output)
{
$path = $input->getOption('path');
$configurationPath = $this->getHelper('configuration')->getConfigurationPath($path);
$dialog = $this->getHelperSet()->get('dialog');
$version = $input->getArgument('version');
$defaultVersion = $this->getLatestVersion();
if (empty($version)) {
$version = $defaultVersion;
}
$output->writeln("<comment>Welcome to the Chamilo $version installation process.</comment>");
if (!is_writable($configurationPath)) {
$output->writeln("<comment>Folder ".$configurationPath." must be writable</comment>");
exit;
}
$sqlFolder = $this->getInstallationPath($version);
if (!is_dir($sqlFolder)) {
$output->writeln("<comment>Sorry you can't install that version of Chamilo :( Supported versions:</comment> <info>".implode(', ', $this->getAvailableVersions()));
exit;
}
if (file_exists($configurationPath.'configuration.php') || file_exists($configurationPath.'configuration.yml')) {
$output->writeln("<comment>There's a Chamilo portal here ".$configurationPath." you must run</comment> <info>chamilo:setup </info><comment>if you want a fresh install.</comment>");
exit;
/*
if (!$dialog->askConfirmation(
$output,
'<question>There is a Chamilo installation located here:</question> '.$configurationPath.' <question>Are you sure you want to continue?</question>(y/N)',
false
)
) {
return;
}
if (!$dialog->askConfirmation(
$output,
'<comment>This will be a fresh installation. Old databases and config files will be deleted. </comment></info> <question>Are you sure?</question>(y/N)',
false
)
) {
return;
}
$this->cleanInstallation($output);*/
}
$avoidVariables = array(
//'main_database', //default is chamilo
'db_glue',
'table_prefix',
'course_folder',
'db_admin_path',
'cdn_enable',
'verbose_backup',
'session_stored_in_db',
'session_lifetime',
'software_name',
'software_url',
'deny_delete_users',
'system_version',
'system_stable'
);
// Getting default configuration parameters in the $_configuration array
require_once api_get_path(SYS_PATH).'main/install/configuration.dist.yml.php';
$newConfigurationArray = array();
foreach ($_configuration as $key => $value) {
if (in_array($key, $avoidVariables)) {
$newConfigurationArray[$key] = $value;
continue;
}
if (!is_array($value)) {
$data = $dialog->ask(
$output,
"Please enter the value of the $key ($value): ",
$value
);
$newConfigurationArray[$key] = $data;
} else {
$newConfigurationArray[$key] = $value;
}
}
$testConnection = $this->testDatabaseConnection($newConfigurationArray['db_host'], $newConfigurationArray['db_user'], $newConfigurationArray['db_password']);
if ($testConnection == 1) {
$output->writeln("<comment>Connection enabled for user: </comment><info>".$newConfigurationArray['db_user']);
} else {
$output->writeln("<error>No access to the database for user:</error><info>".$newConfigurationArray['db_user']."</info>");
exit;
}
$configurationWasSaved = $this->writeConfiguration($newConfigurationArray, $version);
if ($configurationWasSaved) {
global $app;
$app['chamilo.log'] = $app['log.path'].'/chamilo_install.log';
//Installing database
$result = $this->install($version, $newConfigurationArray, $output);
if ($result) {
$this->setDatabaseSettings($newConfigurationArray, $newConfigurationArray['main_database']);
global $_configuration;
$_configuration = $newConfigurationArray;
$this->createAdminUser($newConfigurationArray, $output);
//@todo ask this during installation
$adminInfo = $this->getDefaultAdminUser();
api_set_setting('Institution', 'Portal');
api_set_setting('InstitutionUrl', 'Portal');
api_set_setting('siteName', 'Campus');
api_set_setting('emailAdministrator', $adminInfo['email']);
api_set_setting('administratorSurname', $adminInfo['lastname']);
api_set_setting('administratorName', $adminInfo['firstname']);
api_set_setting('platformLanguage', $adminInfo['language']);
api_set_setting('allow_registration', '1');
api_set_setting('allow_registration_as_teacher', '1');
$versionInfo = $this->getAvailableVersionInfo($version);
$command = $this->getApplication()->find('migrations:migrate');
$arguments = array(
'command' => 'migrations:migrate',
'version' => $versionInfo['hook_to_doctrine_version'],
'--configuration' => $this->getMigrationConfigurationFile()
);
$output->writeln("<comment>Executing migrations:migrate ".$versionInfo['hook_to_doctrine_version']." --configuration=".$this->getMigrationConfigurationFile()."<comment>");
$input = new ArrayInput($arguments);
$command->run($input, $output);
//$output->writeln("<comment>Migration ended succesfully</comment>");
$output->writeln("<comment>Chamilo was successfully installed. Go to your browser and enter:</comment> <info>".$newConfigurationArray['root_web']);
}
}
}
/**
* Default admin info
* @return array
*/
public function getDefaultAdminUser()
{
$adminUser = array(
'lastname' => 'Julio',
'firstname' => 'Montoya',
'username' => 'admin',
'password' => 'admin',
'email' => 'admin@example.org',
'language' => 'english',
'phone' => '6666666'
);
return $adminUser;
}
/**
* Creates an admin user
*
* @param $newConfigurationArray
* @param $output
*
* @return bool
*/
public function createAdminUser($newConfigurationArray, $output)
{
$dialog = $this->getHelperSet()->get('dialog');
//Creating admin user
$adminUser = $this->getDefaultAdminUser();
$output->writeln("<comment>Creating an admin User</comment>");
$userInfo = array();
foreach ($adminUser as $key => $value) {
$data = $dialog->ask(
$output,
"Please enter the $key ($value): ",
$value
);
$userInfo[$key] = $data;
}
//By default admin is = 1 so we update it
$userId = $userInfo['user_id'] = 1;
$userInfo['auth_source'] = 'platform';
$userInfo['password'] = api_get_encrypted_password($userInfo['password']);
$result = \UserManager::update($userInfo);
if ($result) {
\UserManager::add_user_as_admin($userInfo['user_id']);
$output->writeln("<comment>User admin created with id: $userId</comment>");
return true;
}
return false;
}
/**
* @return string
*/
public function getLatestVersion()
{
return '1.10';
}
private function setDatabaseSettings($configuration, $databaseName)
{
// @todo remove this config global. loaded in config-console.php
global $config;
$defaultConnection = array(
'driver' => 'pdo_mysql',
'dbname' => $databaseName,
'user' => $configuration['db_user'],
'password' => $configuration['db_password'],
'host' => $configuration['db_host'],
);
$em = \Doctrine\ORM\EntityManager::create($defaultConnection, $config);
//Fixes some errors
$platform = $em->getConnection()->getDatabasePlatform();
$platform->registerDoctrineTypeMapping('enum', 'string');
$platform->registerDoctrineTypeMapping('set', 'string');
$helpers = array(
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($em->getConnection()),
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($em),
);
foreach ($helpers as $name => $helper) {
$this->getApplication()->getHelperSet()->set($helper, $name);
}
$conn_return = \Database::connect(array(
'server' => $configuration['db_host'],
'username' => $configuration['db_user'],
'password' => $configuration['db_password']
));
$checkConnection = \Database::select_db($databaseName, $conn_return);
}
/**
* Installs Chamilo
*
* @param string $version
* @param array $_configuration
* @param $output
* @return bool
*/
public function install($version, $_configuration, $output)
{
$sqlFolder = $this->getInstallationPath($version);
$databaseMap = $this->getDatabaseMap();
if (isset($databaseMap[$version])) {
$dbInfo = $databaseMap[$version];
$sections = $dbInfo['section'];
foreach ($sections as $sectionData) {
foreach ($sectionData as $dbInfo) {
$databaseName = $dbInfo['name'];
$dbList = $dbInfo['sql'];
$output->writeln("<comment>Creating database</comment> <info>$databaseName ... </info>");
$result = $this->dropAndCreateDatabase($databaseName);
$this->setDatabaseSettings($_configuration, $databaseName);
// Fixing db list
foreach ($dbList as &$db) {
$db = $sqlFolder.$db;
}
//Importing files
if ($result) {
$command = $this->getApplication()->find('dbal:import');
//Importing sql files
$arguments = array(
'command' => 'dbal:import',
'file' => $dbList
);
$input = new ArrayInput($arguments);
$command->run($input, $output);
//Getting extra information about the installation
$output->writeln("<comment>Database </comment><info>$databaseName </info><comment>process ended!</comment>");
}
}
}
if (isset($sections) && isset($sections['course'])) {
//@todo fix this
$this->setDatabaseSettings($_configuration, $sections['main'][0]['name']);
foreach ($sections['course'] as $courseInfo) {
$databaseName = $courseInfo['name'];
$output->writeln("Inserting course database in chamilo: <info>$databaseName</info>");
$this->createCourse($databaseName);
}
}
$output->writeln("<comment>Check your installation status with </comment><info>chamilo:status</info>");
return true;
}
return false;
}
/**
* Creates a course (only an insert in the DB)
* @param string $databaseName
*/
public function createCourse($databaseName)
{
$params = array(
'code' => $databaseName,
'db_name' => $databaseName,
'course_language' => 'english',
'title' => $databaseName,
'visual_code' => $databaseName
);
@\Database::insert(TABLE_MAIN_COURSE, $params);
}
/**
* Creates a Database
* @todo use doctrine?
*
* @return resource
*/
public function dropAndCreateDatabase($databaseName)
{
/*
$command = $this->getApplication()->find('orm:schema-tool:create');
$arguments = array(
'command' => 'orm:schema-tool:create',
);
$input = new ArrayInput($arguments);
$command->run($input, $output);
exit;
*/
$this->dropDatabase($databaseName);
$result = \Database::query("CREATE DATABASE IF NOT EXISTS ".mysql_real_escape_string($databaseName)." DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci");
if ($result) {
return \Database::select_db($databaseName);
}
return false;
}
/**
* Drops a database
* @param string $name
*/
public function dropDatabase($name)
{
\Database::query("DROP DATABASE ".mysql_real_escape_string($name)."");
}
/**
*
* In step 3. Tests establishing connection to the database server.
* If it's a single database environment the function checks if the database exist.
* If the database doesn't exist we check the creation permissions.
*
* @return int 1 when there is no problem;
* 0 when a new database is impossible to be created, then the single/multiple database configuration is impossible too
* -1 when there is no connection established.
*/
public function testDatabaseConnection($dbHostForm, $dbUsernameForm, $dbPassForm)
{
$dbConnect = -1;
//Checking user credentials
if (@\Database::connect(
array('server' => $dbHostForm, 'username' => $dbUsernameForm, 'password' => $dbPassForm)
) !== false
) {
$dbConnect = 1;
} else {
$dbConnect = -1;
}
return $dbConnect; //return 1, if no problems, "0" if, in case we can't create a new DB and "-1" if there is no connection.
}
}