diff --git a/Core/Frameworks/Baikal/Core/Tools.php b/Core/Frameworks/Baikal/Core/Tools.php
index 25f7808..73bb28e 100644
--- a/Core/Frameworks/Baikal/Core/Tools.php
+++ b/Core/Frameworks/Baikal/Core/Tools.php
@@ -45,8 +45,8 @@ class Tools {
# Asserting PDO::SQLite or PDO::MySQL
$aPDODrivers = \PDO::getAvailableDrivers();
- if (!in_array('sqlite', $aPDODrivers, true) && !in_array('mysql', $aPDODrivers, true)) {
- exit('Baikal Fatal Error: Both PDO::sqlite and PDO::mysql are unavailable. One of them at least is required by Baikal.');
+ if (!in_array('sqlite', $aPDODrivers, true) && !in_array('mysql', $aPDODrivers, true) && !in_array('pgsql', $aPDODrivers, true)) {
+ exit('Baikal Fatal Error: None of PDO::sqlite, PDO::mysql or PDO::pgsql are available. One of them at least is required by Baikal.');
}
# Assert that the temp folder is writable
diff --git a/Core/Frameworks/Baikal/Model/Calendar.php b/Core/Frameworks/Baikal/Model/Calendar.php
index c27ba9c..8b55b3b 100644
--- a/Core/Frameworks/Baikal/Model/Calendar.php
+++ b/Core/Frameworks/Baikal/Model/Calendar.php
@@ -202,10 +202,10 @@ class Calendar extends \Flake\Core\Model\Db {
"label" => "Calendar color",
"validation" => "color",
"popover" => [
- "title" => "Calendar color",
- "content" => "This is the color that will be displayed in your CalDAV client.
" .
- "Must be supplied in format '#RRGGBBAA' (alpha channel optional) with hexadecimal values.
" .
- "This value is optional.",
+ "title" => "Calendar color",
+ "content" => "This is the color that will be displayed in your CalDAV client.
" .
+ "Must be supplied in format '#RRGGBBAA' (alpha channel optional) with hexadecimal values.
" .
+ "This value is optional.",
],
]));
@@ -244,7 +244,7 @@ class Calendar extends \Flake\Core\Model\Db {
function hasInstances() {
$rSql = $GLOBALS["DB"]->exec_SELECTquery(
- "count(*)",
+ "count(*) as count",
"calendarinstances",
"calendarid='" . $this->aData["calendarid"] . "'"
);
@@ -254,7 +254,7 @@ class Calendar extends \Flake\Core\Model\Db {
} else {
reset($aRs);
- return $aRs["count(*)"] > 1;
+ return $aRs["count"] > 1;
}
}
diff --git a/Core/Frameworks/Baikal/Model/Calendar/Calendar.php b/Core/Frameworks/Baikal/Model/Calendar/Calendar.php
index 9c75ade..980a318 100644
--- a/Core/Frameworks/Baikal/Model/Calendar/Calendar.php
+++ b/Core/Frameworks/Baikal/Model/Calendar/Calendar.php
@@ -38,7 +38,7 @@ class Calendar extends \Flake\Core\Model\Db {
function hasInstances() {
$rSql = $GLOBALS["DB"]->exec_SELECTquery(
- "count(*)",
+ "count(*) as count",
"calendarinstances",
"calendarid='" . $this->aData["id"] . "'"
);
@@ -48,7 +48,7 @@ class Calendar extends \Flake\Core\Model\Db {
} else {
reset($aRs);
- return $aRs["count(*)"] > 1;
+ return $aRs["count"] > 1;
}
}
diff --git a/Core/Frameworks/Baikal/Model/Config/Database.php b/Core/Frameworks/Baikal/Model/Config/Database.php
index e0035d5..4ce20c0 100644
--- a/Core/Frameworks/Baikal/Model/Config/Database.php
+++ b/Core/Frameworks/Baikal/Model/Config/Database.php
@@ -31,12 +31,16 @@ class Database extends \Baikal\Model\Config {
# Default values
protected $aData = [
"sqlite_file" => PROJECT_PATH_SPECIFIC . "db/db.sqlite",
- "mysql" => false,
+ "backend" => "",
"mysql_host" => "",
"mysql_dbname" => "",
"mysql_username" => "",
"mysql_password" => "",
"encryption_key" => "",
+ "pgsql_host" => "",
+ "pgsql_dbname" => "",
+ "pgsql_username" => "",
+ "pgsql_password" => "",
];
function __construct() {
@@ -46,6 +50,14 @@ class Database extends \Baikal\Model\Config {
function formMorphologyForThisModelInstance() {
$oMorpho = new \Formal\Form\Morphology();
+ $oMorpho->add(new \Formal\Element\Listbox([
+ "prop" => "backend",
+ "label" => "Database Backend",
+ "validation" => "required",
+ "options" => ['sqlite', 'mysql', 'pgsql'],
+ "refreshonchange" => true,
+ ]));
+
$oMorpho->add(new \Formal\Element\Text([
"prop" => "sqlite_file",
"label" => "SQLite file path",
@@ -54,13 +66,6 @@ class Database extends \Baikal\Model\Config {
"help" => "The absolute server path to the SQLite file",
]));
- $oMorpho->add(new \Formal\Element\Checkbox([
- "prop" => "mysql",
- "label" => "Use MySQL",
- "help" => "If checked, Baïkal will use MySQL instead of SQLite.",
- "refreshonchange" => true,
- ]));
-
$oMorpho->add(new \Formal\Element\Text([
"prop" => "mysql_host",
"label" => "MySQL host",
@@ -82,6 +87,27 @@ class Database extends \Baikal\Model\Config {
"label" => "MySQL password",
]));
+ $oMorpho->add(new \Formal\Element\Text([
+ "prop" => "pgsql_host",
+ "label" => "PostgreSQL host",
+ "help" => "Host ip or name, including ':portnumber' if port is not the default one (?)",
+ ]));
+
+ $oMorpho->add(new \Formal\Element\Text([
+ "prop" => "pgsql_dbname",
+ "label" => "PostgreSQL database name",
+ ]));
+
+ $oMorpho->add(new \Formal\Element\Text([
+ "prop" => "pgsql_username",
+ "label" => "PostgreSQL username",
+ ]));
+
+ $oMorpho->add(new \Formal\Element\Password([
+ "prop" => "pgsql_password",
+ "label" => "PostgreSQL password",
+ ]));
+
return $oMorpho;
}
diff --git a/Core/Frameworks/BaikalAdmin/Controller/Install/Database.php b/Core/Frameworks/BaikalAdmin/Controller/Install/Database.php
index 4a57584..fc17997 100644
--- a/Core/Frameworks/BaikalAdmin/Controller/Install/Database.php
+++ b/Core/Frameworks/BaikalAdmin/Controller/Install/Database.php
@@ -38,18 +38,22 @@ class Database extends \Flake\Core\Controller {
if (file_exists(PROJECT_PATH_SPECIFIC . "config.system.php")) {
require_once PROJECT_PATH_SPECIFIC . "config.system.php";
$this->oModel->set('sqlite_file', PROJECT_SQLITE_FILE);
- $this->oModel->set('mysql', PROJECT_DB_MYSQL);
+ $this->oModel->set('backend', PROJECT_DB_BACKEND);
$this->oModel->set('mysql_host', PROJECT_DB_MYSQL_HOST);
$this->oModel->set('mysql_dbname', PROJECT_DB_MYSQL_DBNAME);
$this->oModel->set('mysql_username', PROJECT_DB_MYSQL_USERNAME);
$this->oModel->set('mysql_password', PROJECT_DB_MYSQL_PASSWORD);
+ $this->oModel->set('pgsql_host', PROJECT_DB_PGSQL_HOST);
+ $this->oModel->set('pgsql_dbname', PROJECT_DB_PGSQL_DBNAME);
+ $this->oModel->set('pgsql_username', PROJECT_DB_PGSQL_USERNAME);
+ $this->oModel->set('pgsql_password', PROJECT_DB_PGSQL_PASSWORD);
$this->oModel->set('encryption_key', BAIKAL_ENCRYPTION_KEY);
}
$this->oForm = $this->oModel->formForThisModelInstance([
"close" => false,
- "hook.validation" => [$this, "validateConnection"],
- "hook.morphology" => [$this, "hideMySQLFieldWhenNeeded"],
+ "hook.validation" => [$this, "validateSQLConnection"],
+ "hook.morphology" => [$this, "hideSQLFieldWhenNeeded"],
]);
if ($this->oForm->submitted()) {
@@ -99,11 +103,11 @@ class Database extends \Flake\Core\Controller {
return $oView->render();
}
- function validateConnection($oForm, $oMorpho) {
+ function validateMySQLConnection($oForm, $oMorpho) {
if ($oForm->refreshed()) {
return true;
}
- $bMySQLEnabled = $oMorpho->element("mysql")->value();
+ $bMySQLEnabled = $oMorpho->element("backend")->value() == 'mysql';
if ($bMySQLEnabled) {
$sHost = $oMorpho->element("mysql_host")->value();
@@ -129,7 +133,7 @@ class Database extends \Flake\Core\Controller {
$sMessage .= "
Nothing has been saved. Please, add these tables to the database before pursuing Baïkal initialization.
";
$oForm->declareError(
- $oMorpho->element("mysql"),
+ $oMorpho->element("backend"),
$sMessage
);
} else {
@@ -142,7 +146,7 @@ class Database extends \Flake\Core\Controller {
return true;
} catch (\Exception $e) {
- $oForm->declareError($oMorpho->element("mysql"),
+ $oForm->declareError($oMorpho->element("backend"),
"Baïkal was not able to establish a connexion to the MySQL database as configured.
MySQL says: " . $e->getMessage());
$oForm->declareError($oMorpho->element("mysql_host"));
$oForm->declareError($oMorpho->element("mysql_dbname"));
@@ -211,10 +215,10 @@ class Database extends \Flake\Core\Controller {
function hideMySQLFieldWhenNeeded(\Formal\Form $oForm, \Formal\Form\Morphology $oMorpho) {
if ($oForm->submitted()) {
- $bMySQL = (intval($oForm->postValue("mysql")) === 1);
+ $bMySQL = ($oForm->postValue("backend") == 'mysql');
} else {
// oMorpho won't have the values from the model set on it yet
- $bMySQL = $this->oModel->get("mysql");
+ $bMySQL = $this->oModel->get("backend") == 'mysql';
}
if ($bMySQL === true) {
@@ -226,4 +230,103 @@ class Database extends \Flake\Core\Controller {
$oMorpho->remove("mysql_password");
}
}
+
+ function validatePgSQLConnection($oForm, $oMorpho) {
+ $bPgSqlEnabled = $oMorpho->element("backend")->value() == 'pgsql';
+
+ if ($bPgSqlEnabled) {
+ $sHost = $oMorpho->element("pgsql_host")->value();
+ $sDbname = $oMorpho->element("pgsql_dbname")->value();
+ $sUsername = $oMorpho->element("pgsql_username")->value();
+ $sPassword = $oMorpho->element("pgsql_password")->value();
+
+ try {
+ $oDb = new \Flake\Core\Database\Pgsql(
+ $sHost,
+ $sDbname,
+ $sUsername,
+ $sPassword
+ );
+
+ if (($aMissingTables = \Baikal\Core\Tools::isDBStructurallyComplete($oDb)) !== true) {
+ # Checking if all tables are missing
+ $aRequiredTables = \Baikal\Core\Tools::getRequiredTablesList();
+ if (count($aRequiredTables) !== count($aMissingTables)) {
+ $sMessage = "
Database is not structurally complete.
";
+ $sMessage .= "Missing tables are: " . implode(", ", $aMissingTables) . "
";
+ $sMessage .= "You will find the SQL definition of Baïkal tables in this file: Core/Resources/Db/PgSQL/db.sql
";
+ $sMessage .= "
Nothing has been saved. Please, add these tables to the database before pursuing Baïkal initialization.
";
+
+ $oForm->declareError(
+ $oMorpho->element("backend"),
+ $sMessage
+ );
+ } else {
+ # All tables are missing
+ # We add these tables ourselves to the database, to initialize Baïkal
+ $sSqlDefinition = file_get_contents(PROJECT_PATH_CORERESOURCES . "Db/PgSQL/db.sql");
+ $oDb->getPDO()->exec($sSqlDefinition);
+ }
+ }
+
+ return true;
+ } catch (\Exception $e) {
+ $oForm->declareError(
+ $oMorpho->element("backend"),
+ "Baïkal was not able to establish a connexion to the PostgreSQL database as configured.
PostgreSQL says: " . $e->getMessage()
+ );
+
+ $oForm->declareError(
+ $oMorpho->element("pgsql_host")
+ );
+
+ $oForm->declareError(
+ $oMorpho->element("pgsql_dbname")
+ );
+
+ $oForm->declareError(
+ $oMorpho->element("pgsql_username")
+ );
+
+ $oForm->declareError(
+ $oMorpho->element("pgsql_password")
+ );
+ }
+ }
+ }
+
+ public function validateSQLConnection($oForm, $oMorpho) {
+ if ($oMorpho->element("backend")->value() == 'mysql') {
+ $this->validateMySQLConnection($oForm, $oMorpho);
+ } elseif ($oMorpho->element("backend")->value() == 'pgsql') {
+ $this->validatePgSQLConnection($oForm, $oMorpho);
+ }
+ }
+
+ public function hideSqlFieldWhenNeeded(\Formal\Form $oForm, \Formal\Form\Morphology $oMorpho) {
+ if ($oMorpho->element("backend")->value() == 'mysql') {
+ $this->hideMySQLFieldWhenNeeded($oForm, $oMorpho);
+ } elseif ($oMorpho->element("backend")->value() == 'pgsql') {
+ $this->hidePgSQLFieldWhenNeeded($oForm, $oMorpho);
+ }
+ }
+
+ public function hidePgSQLFieldWhenNeeded(\Formal\Form $oForm, \Formal\Form\Morphology $oMorpho) {
+ if ($oForm->submitted()) {
+ $bPgSQL = ($oForm->postValue("backend")) == 'pgsql';
+ } else {
+ // oMorpho won't have the values from the model set on it yet
+ $bPgSQL = $this->oModel->get("backend") == 'pgsql';
+ }
+
+ if ($bPgSQL === true) {
+ $oMorpho->remove("sqlite_file");
+ $this->hideMySQLFieldWhenNeeded($oForm, $oMorpho);
+ } else {
+ $oMorpho->remove("pgsql_host");
+ $oMorpho->remove("pgsql_dbname");
+ $oMorpho->remove("pgsql_username");
+ $oMorpho->remove("pgsql_password");
+ }
+ }
}
diff --git a/Core/Frameworks/BaikalAdmin/Controller/Install/Initialize.php b/Core/Frameworks/BaikalAdmin/Controller/Install/Initialize.php
index f1cc643..6246bc1 100644
--- a/Core/Frameworks/BaikalAdmin/Controller/Install/Initialize.php
+++ b/Core/Frameworks/BaikalAdmin/Controller/Install/Initialize.php
@@ -82,8 +82,12 @@ class Initialize extends \Flake\Core\Controller {
# Default: PDO::SQLite or PDO::MySQL ?
$aPDODrivers = \PDO::getAvailableDrivers();
- if (!in_array('sqlite', $aPDODrivers)) { # PDO::MySQL is already asserted in \Baikal\Core\Tools::assertEnvironmentIsOk()
- $oDatabaseConfig->set("mysql", true);
+ if (in_array('sqlite', $aPDODrivers)) { # PDO::MySQL is already asserted in \Baikal\Core\Tools::assertEnvironmentIsOk()
+ $oDatabaseConfig->set("backend", 'sqlite');
+ } elseif (in_array('mysql', $aPDODrivers)) {
+ $oDatabaseConfig->set("backend", 'mysql');
+ } else {
+ $oDatabaseConfig->set("backend", 'pgsql');
}
$oDatabaseConfig->persist();
diff --git a/Core/Frameworks/BaikalAdmin/Controller/Install/VersionUpgrade.php b/Core/Frameworks/BaikalAdmin/Controller/Install/VersionUpgrade.php
index d4cd91e..67ded66 100644
--- a/Core/Frameworks/BaikalAdmin/Controller/Install/VersionUpgrade.php
+++ b/Core/Frameworks/BaikalAdmin/Controller/Install/VersionUpgrade.php
@@ -505,6 +505,14 @@ SQL
$this->aSuccess[] = 'Updated default values in calendarinstances table';
}
+ if (version_compare($sVersionFrom, '0.10.0', '<')) {
+ $config = Yaml::parseFile(PROJECT_PATH_CONFIG . "baikal.yaml");
+
+ $oConfig = new \Baikal\Model\Config\Database();
+ $oConfig->set("backend", intval($config['database']['mysql']) === 1 ? 'mysql' : 'sqlite');
+ $oConfig->persist();
+ }
+
$this->updateConfiguredVersion($sVersionTo);
return true;
diff --git a/Core/Frameworks/BaikalAdmin/Controller/Login.php b/Core/Frameworks/BaikalAdmin/Controller/Login.php
index 9b5689c..80c2b5d 100644
--- a/Core/Frameworks/BaikalAdmin/Controller/Login.php
+++ b/Core/Frameworks/BaikalAdmin/Controller/Login.php
@@ -34,7 +34,7 @@ class Login extends \Flake\Core\Controller {
}
function render() {
- $sActionUrl = \Flake\Util\Tools::getCurrentUrl();
+ $sActionUrl = $GLOBALS["ROUTER"]::buildRoute("default", []);
$sSubmittedFlagName = "auth";
$sMessage = "";
diff --git a/Core/Frameworks/BaikalAdmin/Controller/Settings/Database.php b/Core/Frameworks/BaikalAdmin/Controller/Settings/Database.php
index 84d10d5..df7da64 100644
--- a/Core/Frameworks/BaikalAdmin/Controller/Settings/Database.php
+++ b/Core/Frameworks/BaikalAdmin/Controller/Settings/Database.php
@@ -74,61 +74,81 @@ class Database extends \Flake\Core\Controller {
function morphologyHook(\Formal\Form $oForm, \Formal\Form\Morphology $oMorpho) {
if ($oForm->submitted()) {
- $bMySQL = (intval($oForm->postValue("mysql")) === 1);
+ $bMySQL = ($oForm->postValue("backend") == 'mysql');
+ $bPgSQL = ($oForm->postValue("backend") == 'pgsql');
} else {
try {
$config = Yaml::parseFile(PROJECT_PATH_CONFIG . "baikal.yaml");
} catch (\Exception $e) {
error_log('Error reading baikal.yaml file : ' . $e->getMessage());
}
- $bMySQL = $config['database']['mysql'] ?? true;
+ $bMySQL = $config['database']['backend'] == 'mysql';
+ $bPgSQL = $config['database']['backend'] == 'pgsql';
}
- if ($bMySQL === true) {
+ if ($bMySQL === true || $bPgSQL === true) {
$oMorpho->remove("sqlite_file");
- } else {
+ }
+
+ if (!$bMySQL) {
$oMorpho->remove("mysql_host");
$oMorpho->remove("mysql_dbname");
$oMorpho->remove("mysql_username");
$oMorpho->remove("mysql_password");
}
+
+ if (!$bPgSQL) {
+ $oMorpho->remove("pgsql_host");
+ $oMorpho->remove("pgsql_dbname");
+ $oMorpho->remove("pgsql_username");
+ $oMorpho->remove("pgsql_password");
+ }
}
function validationHook(\Formal\Form $oForm, \Formal\Form\Morphology $oMorpho) {
if ($oForm->refreshed()) {
return true;
}
- if (intval($oForm->modelInstance()->get("mysql")) === 1) {
- # We have to check the MySQL connection
- $sHost = $oForm->modelInstance()->get("mysql_host");
- $sDbName = $oForm->modelInstance()->get("mysql_dbname");
- $sUsername = $oForm->modelInstance()->get("mysql_username");
- $sPassword = $oForm->modelInstance()->get("mysql_password");
+ if ($oForm->modelInstance()->get("backend") == 'mysql' || $oForm->modelInstance()->get("backend") == 'pgsql') {
+ $dbBackendName = $oForm->modelInstance()->get("backend") == 'pgsql' ? 'PostgreSQL' : 'MySQL';
+ $dbBackendPrefix = $oForm->modelInstance()->get("backend");
+
+ # We have to check the MySQL or PostgreSQL connection
+ $sHost = $oForm->modelInstance()->get("{$dbBackendPrefix}_host");
+ $sDbName = $oForm->modelInstance()->get("{$dbBackendPrefix}_dbname");
+ $sUsername = $oForm->modelInstance()->get("{$dbBackendPrefix}_username");
+ $sPassword = $oForm->modelInstance()->get("{$dbBackendPrefix}_password");
try {
- $oDB = new \Flake\Core\Database\Mysql(
+ $oDB = (($oForm->modelInstance()->get("backend")) == 'pgsql'
+ ) ? new \Flake\Core\Database\Pgsql(
+ $sHost,
+ $sDbName,
+ $sUsername,
+ $sPassword
+ ) : new \Flake\Core\Database\Mysql(
$sHost,
$sDbName,
$sUsername,
$sPassword
);
} catch (\Exception $e) {
- $sMessage = "MySQL error: " . $e->getMessage();
+ $sMessage = "{$dbBackendName} error: " . $e->getMessage();
$sMessage .= "
Nothing has been saved";
- $oForm->declareError($oMorpho->element("mysql_host"), $sMessage);
- $oForm->declareError($oMorpho->element("mysql_dbname"));
- $oForm->declareError($oMorpho->element("mysql_username"));
- $oForm->declareError($oMorpho->element("mysql_password"));
+ $oForm->declareError($oMorpho->element("{$dbBackendPrefix}_host"), $sMessage);
+ $oForm->declareError($oMorpho->element("{$dbBackendPrefix}_dbname"));
+ $oForm->declareError($oMorpho->element("{$dbBackendPrefix}_username"));
+ $oForm->declareError($oMorpho->element("{$dbBackendPrefix}_password"));
return;
}
if (($aMissingTables = \Baikal\Core\Tools::isDBStructurallyComplete($oDB)) !== true) {
- $sMessage = "MySQL error: These tables, required by Baïkal, are missing: " . implode(", ", $aMissingTables) . "
";
- $sMessage .= "You may want create these tables using the file Core/Resources/Db/MySQL/db.sql";
+ $sMessage = "{$dbBackendName} error: These tables, required by Baïkal, are missing: " . implode(", ", $aMissingTables) . "
";
+ $sMessage .= "You may want create these tables using the file Core/Resources/Db/{$dbBackendName}/db.sql";
$sMessage .= "
Nothing has been saved";
- $oForm->declareError($oMorpho->element("mysql"), $sMessage);
+ $oForm->declareError($oMorpho->element("backend"), $sMessage);
return;
}
diff --git a/Core/Frameworks/Flake/Core/Database/Pgsql.php b/Core/Frameworks/Flake/Core/Database/Pgsql.php
new file mode 100644
index 0000000..8d65054
--- /dev/null
+++ b/Core/Frameworks/Flake/Core/Database/Pgsql.php
@@ -0,0 +1,68 @@
+
+# All rights reserved
+#
+# http://flake.codr.fr
+#
+# This script is part of the Flake project. The Flake
+# project 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 2 of the License, or (at your option) any later version.
+#
+# The GNU General Public License can be found at
+# http://www.gnu.org/copyleft/gpl.html.
+#
+# This script 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.
+#
+# This copyright notice MUST APPEAR in all copies of the script!
+#################################################################
+
+namespace Flake\Core\Database;
+
+class Pgsql extends \Flake\Core\Database {
+ protected $oDb = false; // current DB link
+ protected $debugOutput = false;
+ protected $store_lastBuiltQuery = true;
+ protected $debug_lastBuiltQuery = "";
+ protected $sHost = "";
+ protected $sDbName = "";
+ protected $sUsername = "";
+ protected $sPassword = "";
+
+ public function __construct($sHost, $sDbName, $sUsername, $sPassword) {
+ $this->sHost = $sHost;
+ $this->sDbName = $sDbName;
+ $this->sUsername = $sUsername;
+ $this->sPassword = $sPassword;
+
+ $this->oDb = new \PDO(
+ 'pgsql:host=' . $this->sHost . ';dbname=' . $this->sDbName,
+ $this->sUsername,
+ $this->sPassword
+ );
+ }
+
+ public function tables() {
+ $aTables = [];
+
+ $sSql = "SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname = 'public'";
+ $oStmt = $this->query($sSql);
+
+ while (($aRs = $oStmt->fetch()) !== false) {
+ $aTables[] = array_shift($aRs);
+ }
+
+ asort($aTables);
+ reset($aTables);
+
+ return $aTables;
+ }
+}
diff --git a/Core/Frameworks/Flake/Framework.php b/Core/Frameworks/Flake/Framework.php
index 579e25a..3b3cf5a 100644
--- a/Core/Frameworks/Flake/Framework.php
+++ b/Core/Frameworks/Flake/Framework.php
@@ -163,11 +163,25 @@ class Framework extends \Flake\Core\Framework {
define("PROJECT_PATH_CORE", PROJECT_PATH_ROOT . "Core/");
define("PROJECT_PATH_CORERESOURCES", PROJECT_PATH_CORE . "Resources/");
- define("PROJECT_PATH_SPECIFIC", PROJECT_PATH_ROOT . "Specific/");
- define("PROJECT_PATH_CONFIG", PROJECT_PATH_ROOT . "config/");
define("PROJECT_PATH_FRAMEWORKS", PROJECT_PATH_CORE . "Frameworks/");
define("PROJECT_PATH_WWWROOT", PROJECT_PATH_CORE . "WWWRoot/");
+ // set PROJECT_PATH_CONFIG from BAIKAL_PATH_CONFIG
+ $baikalPathConfig = getenv('BAIKAL_PATH_CONFIG');
+ if ($baikalPathConfig !== false) {
+ define("PROJECT_PATH_CONFIG", $baikalPathConfig);
+ } else {
+ define("PROJECT_PATH_CONFIG", PROJECT_PATH_ROOT . "config/");
+ }
+
+ // set PROJECT_PATH_SPECIFIC from BAIKAL_PATH_CONFIG
+ $baikalPathConfig = getenv('BAIKAL_PATH_SPECIFIC');
+ if ($baikalPathConfig !== false) {
+ define("PROJECT_PATH_SPECIFIC", $baikalPathConfig);
+ } else {
+ define("PROJECT_PATH_SPECIFIC", PROJECT_PATH_ROOT . "Specific/");
+ }
+
require_once PROJECT_PATH_CORE . "Distrib.php";
define("PROJECT_PATH_DOCUMENTROOT", PROJECT_PATH_ROOT . "html/");
@@ -259,8 +273,12 @@ class Framework extends \Flake\Core\Framework {
if (defined("BAIKAL_CONTEXT_INSTALL") && (!isset($config['system']['configured_version']) || $config['system']['configured_version'] === BAIKAL_VERSION)) {
return true;
}
- if ($config['database']['mysql'] === true) {
+ # Config key 'mysql' kept for backwards compatibility
+ $legacyMysql = key_exists('mysql', $config['database']) && $config['database']['mysql'] === true;
+ if ($legacyMysql || $config['database']['backend'] === 'mysql') {
self::initDbMysql($config);
+ } elseif ($config['database']['backend'] === 'pgsql') {
+ self::initDbPgsql($config);
} else {
self::initDbSqlite($config);
}
@@ -325,6 +343,38 @@ class Framework extends \Flake\Core\Framework {
return true;
}
+ protected static function initDbPgsql(array $config) {
+ if (!$config['database']['pgsql_host']) {
+ exit("The constant PROJECT_DB_PGSQL_HOST, containing the PostgreSQL host name, is not set.
You should set it in config/baikal.yaml
");
+ }
+
+ if (!$config['database']['pgsql_dbname']) {
+ exit("The constant PROJECT_DB_PGSQL_DBNAME, containing the PostgreSQL database name, is not set.
You should set it in config/baikal.yaml
");
+ }
+
+ try {
+ $GLOBALS["DB"] = new \Flake\Core\Database\Pgsql(
+ $config['database']['pgsql_host'],
+ $config['database']['pgsql_dbname'],
+ $config['database']['pgsql_username'],
+ $config['database']['pgsql_password']
+ );
+
+ $GLOBALS["DB"]->query("SET NAMES 'UTF8'");
+ } catch (\Exception $e) {
+ $message = "Baïkal was not able to establish a connection to the configured PostgreSQL database (as configured in config/baikal.yaml).";
+ if (!$config['database']['pgsql_username']) {
+ exit("$message Note: The constant PROJECT_DB_PGSQL_USERNAME, containing the PostgreSQL database username, is not set. If your database requires a username you should set it in config/baikal.yaml.
");
+ }
+
+ if ($config['database']['pgsql_password'] === null) {
+ exit("$message Note: The constant PROJECT_DB_PGSQL_PASSWORD, containing the PostgreSQL database password, is not set. If your database requires a password you should set it in config/baikal.yaml.
");
+ }
+
+ exit("$message
");
+ }
+ }
+
static function isDBInitialized() {
return isset($GLOBALS["DB"]) && \Flake\Util\Tools::is_a($GLOBALS["DB"], "\Flake\Core\Database");
}
diff --git a/Core/Resources/Db/PgSQL/db.sql b/Core/Resources/Db/PgSQL/db.sql
new file mode 100644
index 0000000..7335dbb
--- /dev/null
+++ b/Core/Resources/Db/PgSQL/db.sql
@@ -0,0 +1,142 @@
+
+CREATE TABLE addressbooks (
+ id SERIAL PRIMARY KEY,
+ principaluri TEXT,
+ displayname VARCHAR(255),
+ uri TEXT,
+ description TEXT,
+ synctoken INT CHECK (synctoken > 0) NOT NULL DEFAULT '1'
+);
+
+CREATE TABLE cards (
+ id SERIAL PRIMARY KEY,
+ addressbookid INT CHECK (addressbookid > 0) NOT NULL,
+ carddata TEXT,
+ uri TEXT,
+ lastmodified INT CHECK (lastmodified > 0),
+ etag TEXT,
+ size INT CHECK (size > 0) NOT NULL
+);
+
+CREATE TABLE addressbookchanges (
+ id SERIAL PRIMARY KEY,
+ uri TEXT NOT NULL,
+ synctoken INT CHECK (synctoken > 0) NOT NULL,
+ addressbookid INT CHECK (addressbookid > 0) NOT NULL,
+ operation SMALLINT NOT NULL
+);
+
+CREATE INDEX addressbookid_synctoken ON addressbookchanges (addressbookid, synctoken);
+
+CREATE TABLE calendarobjects (
+ id SERIAL PRIMARY KEY,
+ calendardata TEXT,
+ uri TEXT,
+ calendarid INTEGER CHECK (calendarid > 0) NOT NULL,
+ lastmodified INT CHECK (lastmodified > 0),
+ etag TEXT,
+ size INT CHECK (size > 0) NOT NULL,
+ componenttype TEXT,
+ firstoccurence INT CHECK (firstoccurence > 0),
+ lastoccurence INT CHECK (lastoccurence > 0),
+ uid TEXT
+);
+
+CREATE TABLE calendars (
+ id SERIAL PRIMARY KEY,
+ synctoken INTEGER CHECK (synctoken > 0) NOT NULL DEFAULT '1',
+ components TEXT
+);
+
+CREATE TABLE calendarinstances (
+ id SERIAL PRIMARY KEY,
+ calendarid INTEGER CHECK (calendarid > 0) NOT NULL,
+ principaluri TEXT,
+ access SMALLINT NOT NULL DEFAULT '1',
+ displayname VARCHAR(100),
+ uri TEXT,
+ description TEXT,
+ calendarorder INT CHECK (calendarorder >= 0) NOT NULL DEFAULT '0',
+ calendarcolor TEXT,
+ timezone TEXT,
+ transparent SMALLINT NOT NULL DEFAULT '0',
+ share_href TEXT,
+ share_displayname VARCHAR(100),
+ share_invitestatus SMALLINT NOT NULL DEFAULT '2'
+);
+
+CREATE TABLE calendarchanges (
+ id SERIAL PRIMARY KEY,
+ uri TEXT NOT NULL,
+ synctoken INT CHECK (synctoken > 0) NOT NULL,
+ calendarid INT CHECK (calendarid > 0) NOT NULL,
+ operation SMALLINT NOT NULL
+);
+
+CREATE INDEX calendarid_synctoken ON calendarchanges (calendarid, synctoken);
+
+CREATE TABLE calendarsubscriptions (
+ id SERIAL PRIMARY KEY,
+ uri TEXT NOT NULL,
+ principaluri TEXT NOT NULL,
+ source TEXT,
+ displayname VARCHAR(100),
+ refreshrate VARCHAR(10),
+ calendarorder INT CHECK (calendarorder >= 0) NOT NULL DEFAULT '0',
+ calendarcolor TEXT,
+ striptodos SMALLINT NULL,
+ stripalarms SMALLINT NULL,
+ stripattachments SMALLINT NULL,
+ lastmodified INT CHECK (lastmodified > 0)
+);
+
+CREATE TABLE schedulingobjects (
+ id SERIAL PRIMARY KEY,
+ principaluri TEXT,
+ calendardata TEXT,
+ uri TEXT,
+ lastmodified INT CHECK (lastmodified > 0),
+ etag TEXT,
+ size INT CHECK (size > 0) NOT NULL
+);
+CREATE TABLE locks (
+ id SERIAL PRIMARY KEY,
+ owner VARCHAR(100),
+ timeout INTEGER CHECK (timeout > 0),
+ created INTEGER,
+ token TEXT,
+ scope SMALLINT,
+ depth SMALLINT,
+ uri TEXT
+);
+
+CREATE INDEX ON locks (token);
+CREATE INDEX ON locks (uri);
+
+CREATE TABLE principals (
+ id SERIAL PRIMARY KEY,
+ uri TEXT NOT NULL,
+ email TEXT,
+ displayname VARCHAR(80)
+);
+
+CREATE TABLE groupmembers (
+ id SERIAL PRIMARY KEY,
+ principal_id INTEGER CHECK (principal_id > 0) NOT NULL,
+ member_id INTEGER CHECK (member_id > 0) NOT NULL
+);
+
+CREATE TABLE propertystorage (
+ id SERIAL PRIMARY KEY,
+ path TEXT NOT NULL,
+ name TEXT NOT NULL,
+ valuetype INT CHECK (valuetype > 0),
+ value TEXT
+);
+
+CREATE UNIQUE INDEX path_property ON propertystorage (path, name);
+CREATE TABLE users (
+ id SERIAL PRIMARY KEY,
+ username TEXT,
+ digesta1 TEXT
+);
diff --git a/Makefile b/Makefile
index e7a4da1..0ae39c0 100644
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,7 @@ dist: vendor/autoload.php
$(BUILD_FILES) \
--exclude="*.swp" \
$(BUILD_DIR)
+ composer config platform.php 7.2 -d $(BUILD_DIR)
composer install --no-interaction --no-dev -d $(BUILD_DIR)
rm $(BUILD_DIR)/composer.*
cd build; zip -r baikal-$(VERSION).zip baikal/
diff --git a/README.md b/README.md
index 5ec0e76..d4abfc0 100644
--- a/README.md
+++ b/README.md
@@ -27,4 +27,4 @@ Many thanks to Daniel Aleksandersen (@zcode) for greatly improving the quality o
[4]: https://fruux.com/
[5]: https://sabre.io/baikal/upgrade/
[6]: https://github.com/JsBergbau/BaikalAnleitung
-[7]: https://github.com/AlexandreMonroche/BaikalGuide
+[7]: https://github.com/criticalsool/Baikal-Guide-FR
diff --git a/composer.json b/composer.json
index f34d884..eebf3e2 100644
--- a/composer.json
+++ b/composer.json
@@ -17,7 +17,7 @@
"ext-zlib" : "*"
},
"require-dev" : {
- "friendsofphp/php-cs-fixer": "3.51.0",
+ "friendsofphp/php-cs-fixer": "3.52.1",
"phpstan/phpstan": "^1.10"
},
"replace" : {
diff --git a/config/baikal.yaml.dist b/config/baikal.yaml.dist
index 3fd772b..e592f47 100644
--- a/config/baikal.yaml.dist
+++ b/config/baikal.yaml.dist
@@ -11,9 +11,13 @@ system:
base_uri: ''
database:
encryption_key: 5d3f0fa0192e3058ea70f1bb20924add
+ backend: 'mysql'
sqlite_file: "absolute/path/to/Specific/db/db.sqlite"
- mysql: true
mysql_host: 'localhost'
mysql_dbname: 'baikal'
mysql_username: 'baikal'
mysql_password: 'baikal'
+ pgsql_host: 'localhost'
+ pgsql_dbname: 'baikal'
+ pgsql_username: 'baikal'
+ pgsql_password: 'baikal'