00001 <?php
00002
00015
00016
00017
00018
00019 define('INSTALLER_DATA_DIR', 'dbscripts/xml');
00020 define('INSTALLER_DOCS_DIR', 'docs');
00021
00022
00023 define('INSTALLER_ERROR_GENERAL', 1);
00024 define('INSTALLER_ERROR_DB', 2);
00025
00026
00027 define('INSTALLER_DEFAULT_LOCALE', 'en_US');
00028
00029 import('db.DBDataXMLParser');
00030 import('site.Version');
00031 import('site.VersionDAO');
00032 import('config.ConfigParser');
00033
00034 require_once('adodb/adodb-xmlschema.inc.php');
00035
00036 class Installer {
00037
00039 var $descriptor;
00040
00042 var $params;
00043
00045 var $currentVersion;
00046
00048 var $newVersion;
00049
00051 var $dbconn;
00052
00054 var $locale;
00055
00057 var $installedLocales;
00058
00060 var $dataXMLParser;
00061
00063 var $actions;
00064
00066 var $sql;
00067
00069 var $notes;
00070
00072 var $configContents;
00073
00075 var $wroteConfig;
00076
00078 var $errorType;
00079
00081 var $errorMsg;
00082
00084 var $logger;
00085
00086
00092 function Installer($descriptor, $params = array()) {
00093
00094
00095 PluginRegistry::loadAllPlugins();
00096
00097
00098
00099 if (!HookRegistry::call('Installer::Installer', array(&$this, &$descriptor, &$params))) {
00100 $this->descriptor = $descriptor;
00101 $this->params = $params;
00102 $this->actions = array();
00103 $this->sql = array();
00104 $this->notes = array();
00105 $this->wroteConfig = true;
00106 }
00107 }
00108
00112 function isUpgrade() {
00113 die ('ABSTRACT CLASS');
00114 }
00115
00119 function destroy() {
00120 if (isset($this->dataXMLParser)) {
00121 $this->dataXMLParser->destroy();
00122 }
00123
00124 HookRegistry::call('Installer::destroy', array(&$this));
00125 }
00126
00131 function preInstall() {
00132 if (!isset($this->dbconn)) {
00133
00134 $conn = &DBConnection::getInstance();
00135 $this->dbconn = &$conn->getDBConn();
00136
00137 if (!$conn->isConnected()) {
00138 $this->setError(INSTALLER_ERROR_DB, $this->dbconn->errorMsg());
00139 return false;
00140 }
00141 }
00142
00143 if (!isset($this->currentVersion)) {
00144
00145 $versionDao = &DAORegistry::getDAO('VersionDAO');
00146 $this->currentVersion = &$versionDao->getCurrentVersion();
00147 }
00148
00149 if (!isset($this->locale)) {
00150 $this->locale = Locale::getLocale();
00151 }
00152
00153 if (!isset($this->installedLocales)) {
00154 $this->installedLocales = array_keys(Locale::getAllLocales());
00155 }
00156
00157 if (!isset($this->dataXMLParser)) {
00158 $this->dataXMLParser = &new DBDataXMLParser();
00159 $this->dataXMLParser->setDBConn($this->dbconn);
00160 }
00161
00162 $result = true;
00163 HookRegistry::call('Installer::preInstall', array(&$this, &$result));
00164
00165 return $result;
00166 }
00167
00172 function execute() {
00173
00174
00175
00176 @set_time_limit (0);
00177
00178 if (!$this->preInstall()) {
00179 return false;
00180 }
00181
00182 if (!$this->parseInstaller()) {
00183 return false;
00184 }
00185
00186 if (!$this->executeInstaller()) {
00187 return false;
00188 }
00189
00190 if (!$this->postInstall()) {
00191 return false;
00192 }
00193
00194 return $this->updateVersion();
00195 }
00196
00201 function postInstall() {
00202 $result = true;
00203 HookRegistry::call('Installer::postInstall', array(&$this, &$result));
00204 return $result;
00205 }
00206
00207
00212 function log($message) {
00213 if (isset($this->logger)) {
00214 call_user_func(array($this->logger, 'log'), $message);
00215 }
00216 }
00217
00218
00219
00220
00221
00222
00227 function parseInstaller() {
00228
00229 $this->log(sprintf('load: %s', $this->descriptor));
00230 $xmlParser = &new XMLParser();
00231 $installTree = $xmlParser->parse(INSTALLER_DATA_DIR . '/' . $this->descriptor);
00232 if (!$installTree) {
00233
00234 $xmlParser->destroy();
00235 $this->setError(INSTALLER_ERROR_GENERAL, 'installer.installFileError');
00236 return false;
00237 }
00238
00239 $versionString = $installTree->getAttribute('version');
00240 if (isset($versionString)) {
00241 $this->newVersion = &Version::fromString($versionString);
00242 $this->newVersion->setCurrent(1);
00243 } else {
00244 $this->newVersion = $this->currentVersion;
00245 }
00246
00247
00248 $this->parseInstallNodes($installTree);
00249 $xmlParser->destroy();
00250
00251 $result = $this->getErrorType() == 0;
00252
00253 HookRegistry::call('Installer::parseInstaller', array(&$this, &$result));
00254 return $result;
00255 }
00256
00261 function executeInstaller() {
00262 $this->log(sprintf('version: %s', $this->newVersion->getVersionString()));
00263 foreach ($this->actions as $action) {
00264 if (!$this->executeAction($action)) {
00265 return false;
00266 }
00267 }
00268
00269 $result = true;
00270 HookRegistry::call('Installer::executeInstaller', array(&$this, &$result));
00271
00272 return $result;
00273 }
00274
00279 function updateVersion() {
00280 if ($this->newVersion->compare($this->currentVersion) > 0) {
00281 if ($this->getParam('manualInstall')) {
00282
00283 return $this->executeSQL(sprintf('INSERT INTO versions (major, minor, revision, build, date_installed, current) VALUES (%d, %d, %d, %d, NOW(), 1)', $this->newVersion->getMajor(), $this->newVersion->getMinor(), $this->newVersion->getRevision(), $this->newVersion->getBuild()));
00284 } else {
00285 $versionDao = &DAORegistry::getDAO('VersionDAO');
00286 if (!$versionDao->insertVersion($this->newVersion)) {
00287 return false;
00288 }
00289 }
00290 }
00291
00292 $result = true;
00293 HookRegistry::call('Installer::updateVersion', array(&$this, &$result));
00294
00295 return $result;
00296 }
00297
00298
00299
00300
00301
00302
00307 function parseInstallNodes(&$installTree) {
00308 foreach ($installTree->getChildren() as $node) {
00309 switch ($node->getName()) {
00310 case 'schema':
00311 case 'data':
00312 case 'code':
00313 case 'note':
00314 $this->addInstallAction($node);
00315 break;
00316 case 'upgrade':
00317 $minVersion = $node->getAttribute('minversion');
00318 $maxVersion = $node->getAttribute('maxversion');
00319 if ((!isset($minVersion) || $this->currentVersion->compare($minVersion) >= 0) && (!isset($maxVersion) || $this->currentVersion->compare($maxVersion) <= 0)) {
00320 $this->parseInstallNodes($node);
00321 }
00322 break;
00323 }
00324 }
00325 }
00326
00331 function addInstallAction(&$node) {
00332 $fileName = $node->getAttribute('file');
00333
00334 if (!isset($fileName)) {
00335 $this->actions[] = array('type' => $node->getName(), 'file' => null, 'attr' => $node->getAttributes());
00336
00337 } else if (strstr($fileName, '{$installedLocale}')) {
00338
00339 foreach ($this->installedLocales as $thisLocale) {
00340 $newFileName = str_replace('{$installedLocale}', $thisLocale, $fileName);
00341 $this->actions[] = array('type' => $node->getName(), 'file' => $newFileName, 'attr' => $node->getAttributes());
00342 }
00343
00344 } else {
00345 $newFileName = str_replace('{$locale}', $this->locale, $fileName);
00346 if (!file_exists(INSTALLER_DATA_DIR . '/'. $newFileName)) {
00347
00348 $newFileName = str_replace('{$locale}', INSTALLER_DEFAULT_LOCALE, $fileName);
00349 }
00350
00351 $this->actions[] = array('type' => $node->getName(), 'file' => $newFileName, 'attr' => $node->getAttributes());
00352 }
00353 }
00354
00355
00356
00357
00358
00359
00365 function executeAction($action) {
00366 switch ($action['type']) {
00367 case 'schema':
00368 $fileName = INSTALLER_DATA_DIR . '/'. $action['file'];
00369 $this->log(sprintf('schema: %s', $action['file']));
00370
00371 require_once('adodb/adodb-xmlschema.inc.php');
00372 $schemaXMLParser = &new adoSchema($this->dbconn, $this->dbconn->charSet);
00373 $sql = $schemaXMLParser->parseSchema($fileName);
00374 $schemaXMLParser->destroy();
00375
00376 if ($sql) {
00377 return $this->executeSQL($sql);
00378 } else {
00379 $this->setError(INSTALLER_ERROR_DB, str_replace('{$file}', $fileName, Locale::translate('installer.installParseDBFileError')));
00380 return false;
00381 }
00382 break;
00383 case 'data':
00384 $fileName = INSTALLER_DATA_DIR . '/'. $action['file'];
00385 $this->log(sprintf('data: %s', $action['file']));
00386 $sql = $this->dataXMLParser->parseData($fileName);
00387 if ($sql) {
00388 return $this->executeSQL($sql);
00389 } else {
00390 $this->setError(INSTALLER_ERROR_DB, str_replace('{$file}', $fileName, Locale::translate('installer.installParseDBFileError')));
00391 return false;
00392 }
00393 break;
00394 case 'code':
00395 $this->log(sprintf('code: %s %s::%s', isset($action['file']) ? $action['file'] : 'Installer', isset($action['attr']['class']) ? $action['attr']['class'] : 'Installer', $action['attr']['function']));
00396
00397 if (isset($action['file'])) {
00398 require_once($action['file']);
00399 }
00400 if (isset($action['attr']['class'])) {
00401 return call_user_func(array($action['attr']['class'], $action['attr']['function']), $this);
00402 } else {
00403 return call_user_func(array(&$this, $action['attr']['function']));
00404 }
00405 break;
00406 case 'note':
00407 $this->log(sprintf('note: %s', $action['file']));
00408 $this->notes[] = join('', file(INSTALLER_DOCS_DIR . '/' . $action['file']));
00409 break;
00410 }
00411
00412 return true;
00413 }
00414
00420 function executeSQL($sql) {
00421 if (is_array($sql)) {
00422 foreach($sql as $stmt) {
00423 if (!$this->executeSQL($stmt)) {
00424 return false;
00425 }
00426 }
00427 } else {
00428 if ($this->getParam('manualInstall')) {
00429 $this->sql[] = $sql;
00430
00431 } else {
00432 $this->dbconn->execute($sql);
00433 if ($this->dbconn->errorNo() != 0) {
00434 $this->setError(INSTALLER_ERROR_DB, $this->dbconn->errorMsg());
00435 return false;
00436 }
00437 }
00438 }
00439
00440 return true;
00441 }
00442
00448 function updateConfig($configParams) {
00449
00450 $configParser = &new ConfigParser();
00451 if (!$configParser->updateConfig(Config::getConfigFileName(), $configParams)) {
00452
00453 $this->setError(INSTALLER_ERROR_GENERAL, 'installer.configFileError');
00454 return false;
00455 }
00456
00457 $this->configContents = $configParser->getFileContents();
00458 if (!$configParser->writeConfig(Config::getConfigFileName())) {
00459 $this->wroteConfig = false;
00460 }
00461
00462 return true;
00463 }
00464
00465
00466
00467
00468
00469
00475 function getParam($name) {
00476 return isset($this->params[$name]) ? $this->params[$name] : null;
00477 }
00478
00483 function &getCurrentVersion() {
00484 return $this->currentVersion;
00485 }
00486
00491 function &getNewVersion() {
00492 return $this->newVersion;
00493 }
00494
00499 function getSQL() {
00500 return $this->sql;
00501 }
00502
00507 function getNotes() {
00508 return $this->notes;
00509 }
00510
00515 function getConfigContents() {
00516 return $this->configContents;
00517 }
00518
00523 function wroteConfig() {
00524 return $this->wroteConfig;
00525 }
00526
00535 function getErrorType() {
00536 return isset($this->errorType) ? $this->errorType : 0;
00537 }
00538
00545 function getErrorMsg() {
00546 return $this->errorMsg;
00547 }
00548
00553 function getErrorString() {
00554 switch ($this->getErrorType()) {
00555 case INSTALLER_ERROR_DB:
00556 return 'DB: ' . $this->getErrorMsg();
00557 default:
00558 return Locale::translate($this->getErrorMsg());
00559 }
00560 }
00561
00567 function setError($type, $msg) {
00568 $this->errorType = $type;
00569 $this->errorMsg = $msg;
00570 }
00571
00576 function setLogger(&$logger) {
00577 $this->logger = $logger;
00578 }
00579
00580 }
00581
00582 ?>