diff --git a/.gitignore b/.gitignore
index 69538d1e4826a5d60138f93272f3ed31843a1250..f98caa0f31463538507330f8a3d81d8f4fe015ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,3 +24,4 @@ Thumbs.db
 .project
 .idea/
 *.iml
+test_database.sqlite
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e56ec2433a61b73e16969e7903f557cd2143cc05..e95d0a2dbb9dc3fb260ed69adb0483e272626f7f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -12,6 +12,7 @@ test:
     - composer install -o  --no-interaction --no-progress --prefer-dist
     - mkdir tpl_c
     - php vendor/bin/php-cs-fixer fix --verbose --dry-run
+    - APP_ENV=test bin/doctrine migrations:migrate --no-interaction -vvv
     - vendor/bin/phpunit --bootstrap app/tests/bootstrap.php --debug app/tests
   cache:
     paths:
diff --git a/admin/migration.php b/admin/migration.php
index d3e6237c67e2d222b7b84a0f78107cf38a2f976a..8578437685498f2d0c5ad00d7122144a17dd061f 100644
--- a/admin/migration.php
+++ b/admin/migration.php
@@ -17,116 +17,64 @@
  * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
  */
 
-use Framadate\Migration\AddColumn_collect_mail_In_poll;
-use Framadate\Migration\AddColumn_hidden_In_poll_For_0_9;
-use Framadate\Migration\AddColumn_mail_In_vote;
-use Framadate\Migration\AddColumn_receiveNewComments_For_0_9;
-use Framadate\Migration\AddColumn_uniqId_In_vote_For_0_9;
-use Framadate\Migration\AddColumn_ValueMax_In_poll_For_1_1;
-use Framadate\Migration\AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9;
-use Framadate\Migration\Alter_Comment_table_adding_date;
-use Framadate\Migration\Alter_Comment_table_for_name_length;
-use Framadate\Migration\Fix_MySQL_No_Zero_Date;
-use Framadate\Migration\From_0_0_to_0_8_Migration;
-use Framadate\Migration\From_0_8_to_0_9_Migration;
-use Framadate\Migration\Generate_uniqId_for_old_votes;
-use Framadate\Migration\Increase_pollId_size;
-use Framadate\Migration\Migration;
-use Framadate\Migration\RPadVotes_from_0_8;
+use Doctrine\DBAL\Migrations\Configuration\Configuration;
+use Doctrine\DBAL\Migrations\Migration;
+use Doctrine\DBAL\Migrations\OutputWriter;
+use Doctrine\DBAL\Migrations\Tools\Console\Helper\MigrationStatusInfosHelper;
 use Framadate\Utils;
 
-include_once __DIR__ . '/../app/inc/init.php';
+require_once __DIR__ . '/../app/inc/init.php';
 
-set_time_limit(300);
+class MigrationLogger {
+    private $log;
 
-// List a Migration sub classes to execute
-$migrations = [
-    new From_0_0_to_0_8_Migration(),
-    new From_0_8_to_0_9_Migration(),
-    new AddColumn_receiveNewComments_For_0_9(),
-    new AddColumn_uniqId_In_vote_For_0_9(),
-    new AddColumn_hidden_In_poll_For_0_9(),
-    new AddColumn_ValueMax_In_poll_For_1_1(),
-    new Generate_uniqId_for_old_votes(),
-    new RPadVotes_from_0_8(),
-    new Alter_Comment_table_for_name_length(),
-    new Alter_Comment_table_adding_date(),
-    new AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9(),
-    new Increase_pollId_size(),
-    new AddColumn_ValueMax_In_poll_For_1_1(),
-    new Fix_MySQL_No_Zero_Date(),
-    new AddColumn_mail_In_vote(),
-    new AddColumn_collect_mail_In_poll()
-];
-// ---------------------------------------
-
-// Check if MIGRATION_TABLE already exists
-/** @var \Framadate\FramaDB $connect */
-$tables = $connect->allTables();
-$pdo = $connect->getPDO();
-$prefixedMigrationTable = Utils::table(MIGRATION_TABLE);
-
-if (!in_array($prefixedMigrationTable, $tables, true)) {
-    $pdo->exec('
-CREATE TABLE IF NOT EXISTS `' . $prefixedMigrationTable . '` (
-  `id`   INT(11)  UNSIGNED NOT NULL AUTO_INCREMENT,
-  `name` TEXT              NOT NULL,
-  `execute_date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  PRIMARY KEY (`id`)
-)
-  ENGINE = MyISAM
-  DEFAULT CHARSET = utf8;');
-}
-
-$selectStmt = $pdo->prepare('SELECT id FROM `' . $prefixedMigrationTable . '` WHERE name=?');
-$insertStmt = $pdo->prepare('INSERT INTO `' . $prefixedMigrationTable . '` (name) VALUES (?)');
-$countSucceeded = 0;
-$countFailed = 0;
-$countSkipped = 0;
-
-// Loop on every Migration sub classes
-$success = [];
-$fail = [];
-foreach ($migrations as $migration) {
-    $className = get_class($migration);
-
-    // Check if $className is a Migration sub class
-    if (!$migration instanceof Migration) {
-        $smarty->assign('error', 'The class ' . $className . ' is not a sub class of Framadate\\Migration\\Migration.');
-        $smarty->display('error.tpl');
-        exit;
+    public function __construct()
+    {
+        $this->log = '';
     }
 
-    // Check if the Migration is already executed
-    $selectStmt->execute([$className]);
-    $executed = $selectStmt->rowCount();
-    $selectStmt->closeCursor();
+    public function addLine($message)
+    {
+        $this->log .= $message . "\n";
+    }
 
-    if (!$executed && $migration->preCondition($pdo)) {
-        $migration->execute($pdo);
-        if ($insertStmt->execute([$className])) {
-            $countSucceeded++;
-            $success[] = $migration->description();
-        } else {
-            $countFailed++;
-            $fail[] = $migration->description();
-        }
-    } else {
-        $countSkipped++;
+    public function getLog()
+    {
+        return $this->log;
     }
 }
 
-$countTotal = $countSucceeded + $countFailed + $countSkipped;
+$executing = false;
+$migration = null;
+$output = '';
 
-$smarty->assign('success', $success);
-$smarty->assign('fail', $fail);
+if (isset($_POST['execute'])) {
+    $executing = true;
+}
 
-$smarty->assign('countSucceeded', $countSucceeded);
-$smarty->assign('countFailed', $countFailed);
-$smarty->assign('countSkipped', $countSkipped);
-$smarty->assign('countTotal', $countTotal);
-$smarty->assign('time', $total_time = round((microtime(true)-$_SERVER['REQUEST_TIME_FLOAT']), 4));
+$migrationsDirectory = __DIR__ . '/../app/classes/Framadate/Migrations';
+$log = new MigrationLogger();
+
+$configuration = new Configuration($connect, new OutputWriter(function ($message) use ($log) {
+    $log->addLine($message);
+}));
+$configuration->setMigrationsTableName(Utils::table(MIGRATION_TABLE) . '_new');
+$configuration->setMigrationsDirectory($migrationsDirectory);
+$configuration->setMigrationsNamespace('DoctrineMigrations');
+$configuration->registerMigrationsFromDirectory($migrationsDirectory);
+
+if ($executing) {
+    $migration = new Migration($configuration);
+    $migration->migrate();
+    $output = trim(strip_tags($log->getLog()));
+}
+$infos = (new MigrationStatusInfosHelper($configuration))->getMigrationsInfos();
 
+$smarty->assign('countTotal', $infos['Available Migrations']);
+$smarty->assign('countExecuted', $infos['Executed Migrations']);
+$smarty->assign('countWaiting', $infos['New Migrations']);
+$smarty->assign('executing', $executing);
 $smarty->assign('title', __('Admin', 'Migration'));
-
+$smarty->assign('output', $output);
+$smarty->assign('time', round((microtime(true)-$_SERVER['REQUEST_TIME_FLOAT']), 4));
 $smarty->display('admin/migration.tpl');
diff --git a/app/classes/Framadate/AbstractMigration.php b/app/classes/Framadate/AbstractMigration.php
new file mode 100644
index 0000000000000000000000000000000000000000..dd79f965ecead642a19036eddbf07cea5e586a50
--- /dev/null
+++ b/app/classes/Framadate/AbstractMigration.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+namespace Framadate;
+
+use Doctrine\DBAL\Migrations\AbstractMigration as DoctrineAbstractMigration;
+use Doctrine\DBAL\Schema\Schema;
+
+abstract class AbstractMigration extends DoctrineAbstractMigration
+{
+    /**
+     * @param Schema $schema
+     * @param $class
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @return bool
+     */
+    public function legacyCheck(Schema $schema, $class)
+    {
+        /**
+         * If there's no legacy table, we can go on
+         */
+        if (!$schema->hasTable(Utils::table(MIGRATION_TABLE))) {
+            return false;
+        }
+
+        $migration_table = $schema->getTable(Utils::table(MIGRATION_TABLE));
+        /**
+         * We check the migration table
+         */
+        if ($migration_table->hasColumn('name')) {
+            /** @var $stmt \Doctrine\DBAL\Driver\Statement */
+            $stmt = $this->connection->prepare('SELECT * FROM ' . Utils::table(MIGRATION_TABLE) . ' WHERE name = ?');
+            $stmt->execute([$class]);
+            return $stmt->rowCount() > 0;
+        }
+        return false;
+    }
+}
diff --git a/app/classes/Framadate/FramaDB.php b/app/classes/Framadate/FramaDB.php
index bed632733043826b378e77e84edd6b776972c676..9d477d9fe948a579a177f1636ea9157ae30afdf0 100644
--- a/app/classes/Framadate/FramaDB.php
+++ b/app/classes/Framadate/FramaDB.php
@@ -42,11 +42,25 @@ class FramaDB {
     /**
      * Find all tables in database.
      *
-     * @return array The array of table names
+     * @return array|false The array of table names
      */
-    function allTables() {
-        $result = $this->pdo->query('SHOW TABLES');
-        $schemas = $result->fetchAll(\PDO::FETCH_COLUMN);
+    public function allTables()
+    {
+        $driver = $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
+        switch ($driver) {
+            case 'mysql':
+                $result = $this->pdo->query('SHOW TABLES');
+                $schemas = $result->fetchAll(\PDO::FETCH_COLUMN);
+                break;
+            case 'pgsql':
+                $result = $this->pdo->query(
+                    "SELECT table_name FROM information_schema.tables WHERE table_schema='public'"
+                );
+                $schemas = $result->fetchAll(\PDO::FETCH_COLUMN);
+                break;
+            default:
+                return false;
+        }
 
         return $schemas;
     }
diff --git a/app/classes/Framadate/Migration/AddColumn_hidden_In_poll_For_0_9.php b/app/classes/Framadate/Migration/AddColumn_hidden_In_poll_For_0_9.php
deleted file mode 100644
index f8c3eac6acb3ef219bb8c2bd822ee82f100d3da3..0000000000000000000000000000000000000000
--- a/app/classes/Framadate/Migration/AddColumn_hidden_In_poll_For_0_9.php
+++ /dev/null
@@ -1,75 +0,0 @@
-<?php
-/**
- * This software is governed by the CeCILL-B license. If a copy of this license
- * is not distributed with this file, you can obtain one at
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
- *
- * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
- * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
- *
- * =============================
- *
- * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
- * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
- *
- * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
- * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
- */
-namespace Framadate\Migration;
-
-use Framadate\Utils;
-
-/**
- * This migration adds the field hidden on the poll table.
- *
- * @package Framadate\Migration
- * @version 0.9
- */
-class AddColumn_hidden_In_poll_For_0_9 implements Migration {
-    function __construct() {
-    }
-
-    /**
-     * This method should describe in english what is the purpose of the migration class.
-     *
-     * @return string The description of the migration class
-     */
-    function description() {
-        return 'Add column "hidden" in table "vote" for version 0.9';
-    }
-
-    /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the Migration should be executed.
-     */
-    function preCondition(\PDO $pdo) {
-        $stmt = $pdo->query('SHOW TABLES');
-        $tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
-
-        // Check if tables of v0.9 are presents
-        $diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables);
-        return count($diff) === 0;
-    }
-
-    /**
-     * This method is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the execution succeeded
-     */
-    function execute(\PDO $pdo) {
-        $this->alterPollTable($pdo);
-
-        return true;
-    }
-
-    private function alterPollTable(\PDO $pdo) {
-        $pdo->exec('
-        ALTER TABLE `' . Utils::table('poll') . '`
-        ADD `hidden` TINYINT( 1 ) NOT NULL DEFAULT "0"');
-    }
-}
diff --git a/app/classes/Framadate/Migration/AddColumn_receiveNewComments_For_0_9.php b/app/classes/Framadate/Migration/AddColumn_receiveNewComments_For_0_9.php
deleted file mode 100644
index 9863e26e64411bb095a3cc6f4de3002c2087946b..0000000000000000000000000000000000000000
--- a/app/classes/Framadate/Migration/AddColumn_receiveNewComments_For_0_9.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-/**
- * This software is governed by the CeCILL-B license. If a copy of this license
- * is not distributed with this file, you can obtain one at
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
- *
- * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
- * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
- *
- * =============================
- *
- * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
- * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
- *
- * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
- * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
- */
-namespace Framadate\Migration;
-
-use Framadate\Utils;
-
-/**
- * This migration adds the field receiveNewComments on the poll table.
- *
- * @package Framadate\Migration
- * @version 0.9
- */
-class AddColumn_receiveNewComments_For_0_9 implements Migration {
-    function __construct() {
-    }
-
-    /**
-     * This method should describe in english what is the purpose of the migration class.
-     *
-     * @return string The description of the migration class
-     */
-    function description() {
-        return 'Add column "receiveNewComments" for version 0.9';
-    }
-
-    /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the Migration should be executed.
-     */
-    function preCondition(\PDO $pdo) {
-        $stmt = $pdo->query('SHOW TABLES');
-        $tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
-
-        // Check if tables of v0.9 are presents
-        $diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables);
-        return count($diff) === 0;
-    }
-
-    /**
-     * This method is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the execution succeeded
-     */
-    function execute(\PDO $pdo) {
-        $this->alterPollTable($pdo);
-
-        return true;
-    }
-
-    private function alterPollTable(\PDO $pdo) {
-        $pdo->exec('
-ALTER TABLE `' . Utils::table('poll') . '`
-        ADD `receiveNewComments` TINYINT(1) DEFAULT \'0\'
-        AFTER `receiveNewVotes`');
-    }
-}
diff --git a/app/classes/Framadate/Migration/AddColumn_uniqId_In_vote_For_0_9.php b/app/classes/Framadate/Migration/AddColumn_uniqId_In_vote_For_0_9.php
deleted file mode 100644
index 2da2e49844170ecbfd0e577df6a8153e7f17832f..0000000000000000000000000000000000000000
--- a/app/classes/Framadate/Migration/AddColumn_uniqId_In_vote_For_0_9.php
+++ /dev/null
@@ -1,77 +0,0 @@
-<?php
-/**
- * This software is governed by the CeCILL-B license. If a copy of this license
- * is not distributed with this file, you can obtain one at
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
- *
- * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
- * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
- *
- * =============================
- *
- * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
- * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
- *
- * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
- * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
- */
-namespace Framadate\Migration;
-
-use Framadate\Utils;
-
-/**
- * This migration adds the field uniqId on the vote table.
- *
- * @package Framadate\Migration
- * @version 0.9
- */
-class AddColumn_uniqId_In_vote_For_0_9 implements Migration {
-    function __construct() {
-    }
-
-    /**
-     * This method should describe in english what is the purpose of the migration class.
-     *
-     * @return string The description of the migration class
-     */
-    function description() {
-        return 'Add column "uniqId" in table "vote" for version 0.9';
-    }
-
-    /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the Migration should be executed.
-     */
-    function preCondition(\PDO $pdo) {
-        $stmt = $pdo->query('SHOW TABLES');
-        $tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
-
-        // Check if tables of v0.9 are presents
-        $diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables);
-        return count($diff) === 0;
-    }
-
-    /**
-     * This method is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the execution succeeded
-     */
-    function execute(\PDO $pdo) {
-        $this->alterPollTable($pdo);
-
-        return true;
-    }
-
-    private function alterPollTable(\PDO $pdo) {
-        $pdo->exec('
-        ALTER TABLE `' . Utils::table('vote') . '`
-        ADD `uniqId` CHAR(16) NOT NULL
-        AFTER `id`,
-        ADD INDEX (`uniqId`) ;');
-    }
-}
diff --git a/app/classes/Framadate/Migration/AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9.php b/app/classes/Framadate/Migration/AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9.php
deleted file mode 100644
index 93893a160c339ef4d8abc7a012daa5bd7f3d0841..0000000000000000000000000000000000000000
--- a/app/classes/Framadate/Migration/AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-/**
- * This software is governed by the CeCILL-B license. If a copy of this license
- * is not distributed with this file, you can obtain one at
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
- *
- * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
- * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
- *
- * =============================
- *
- * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
- * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
- *
- * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
- * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
- */
-namespace Framadate\Migration;
-
-use Framadate\Utils;
-
-/**
- * This migration adds the fields password_hash and results_publicly_visible on the poll table.
- *
- * @package Framadate\Migration
- * @version 0.9
- */
-class AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9 implements Migration {
-    function __construct() {
-    }
-
-    /**
-     * This method should describe in english what is the purpose of the migration class.
-     *
-     * @return string The description of the migration class
-     */
-    function description() {
-        return 'Add columns "password_hash" and "results_publicly_visible" in table "vote" for version 0.9';
-    }
-
-    /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the Migration should be executed.
-     */
-    function preCondition(\PDO $pdo) {
-        $stmt = $pdo->query('SHOW TABLES');
-        $tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
-
-        // Check if tables of v0.9 are presents
-        $diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables);
-        return count($diff) === 0;
-    }
-
-    /**
-     * This method is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the execution succeeded
-     */
-    function execute(\PDO $pdo) {
-        $this->alterPollTable($pdo);
-
-        return true;
-    }
-
-    private function alterPollTable(\PDO $pdo) {
-        $pdo->exec('
-        ALTER TABLE `' . Utils::table('poll') . '`
-        ADD `password_hash` VARCHAR(255) NULL DEFAULT NULL ,
-        ADD `results_publicly_visible` TINYINT(1) NULL DEFAULT NULL');
-    }
-}
diff --git a/app/classes/Framadate/Migration/Fix_MySQL_No_Zero_Date.php b/app/classes/Framadate/Migration/Fix_MySQL_No_Zero_Date.php
deleted file mode 100644
index 6eae5921a266dc87eddc030407bd0371c1ba1c29..0000000000000000000000000000000000000000
--- a/app/classes/Framadate/Migration/Fix_MySQL_No_Zero_Date.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-/**
- * This software is governed by the CeCILL-B license. If a copy of this license
- * is not distributed with this file, you can obtain one at
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
- *
- * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
- * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
- *
- * =============================
- *
- * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
- * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
- *
- * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
- * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
- */
-namespace Framadate\Migration;
-
-use Framadate\Utils;
-
-/**
- * This migration sets Poll.end_date to NULL by default
- *
- * @package Framadate\Migration
- * @version 1.1
- */
-class Fix_MySQL_No_Zero_Date implements Migration {
-    function __construct() {
-    }
-
-    /**
-     * This method should describe in english what is the purpose of the migration class.
-     *
-     * @return string The description of the migration class
-     */
-    function description() {
-        return 'Sets Poll end_date to NULL by default (work around MySQL NO_ZERO_DATE)';
-    }
-
-    /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true if the Migration should be executed.
-     */
-    function preCondition(\PDO $pdo) {
-        $stmt = $pdo->prepare("SELECT Column_Default from Information_Schema.Columns where Table_Name = ? AND Column_Name = ?;");
-        $stmt->bindValue(1, Utils::table('poll'));
-        $stmt->bindValue(2, 'end_date');
-        $stmt->execute();
-        $default = $stmt->fetch(\PDO::FETCH_COLUMN);
-
-        $driver_name = $pdo->getAttribute(\PDO::ATTR_DRIVER_NAME);
-
-        return $default !== null && $driver_name === 'mysql';
-    }
-
-    /**
-     * This method is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool|void if the execution succeeded
-     */
-    function execute(\PDO $pdo) {
-        $pdo->exec('ALTER TABLE ' . Utils::table('poll') . ' MODIFY end_date TIMESTAMP NULL DEFAULT NULL;');
-    }
-}
diff --git a/app/classes/Framadate/Migration/From_0_0_to_0_8_Migration.php b/app/classes/Framadate/Migration/From_0_0_to_0_8_Migration.php
deleted file mode 100644
index 092de919938c368ea21eff08a2bf3630b1044d68..0000000000000000000000000000000000000000
--- a/app/classes/Framadate/Migration/From_0_0_to_0_8_Migration.php
+++ /dev/null
@@ -1,108 +0,0 @@
-<?php
-/**
- * This software is governed by the CeCILL-B license. If a copy of this license
- * is not distributed with this file, you can obtain one at
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
- *
- * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
- * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
- *
- * =============================
- *
- * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
- * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
- *
- * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
- * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
- */
-namespace Framadate\Migration;
-
-use Framadate\Utils;
-
-/**
- * Class From_0_0_to_0_8_Migration
- *
- * @package Framadate\Migration
- * @version 0.8
- */
-class From_0_0_to_0_8_Migration implements Migration {
-    function __construct() {
-    }
-
-    /**
-     * This method should describe in english what is the purpose of the migration class.
-     *
-     * @return string The description of the migration class
-     */
-    function description() {
-        return 'First installation of the Framadate application (v0.8)';
-    }
-
-    /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the Migration should be executed.
-     */
-    function preCondition(\PDO $pdo) {
-        $stmt = $pdo->query('SHOW TABLES like \'' . TABLENAME_PREFIX . '%\'');  //issue187 : pouvoir installer framadate dans une base contenant d'autres tables.
-        $tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
-
-        // Check if there is no tables but the MIGRATION_TABLE one
-        $diff = array_diff($tables, [Utils::table(MIGRATION_TABLE)]);
-        return count($diff) === 0;
-    }
-
-    /**
-     * This method is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the execution succeeded
-     */
-    function execute(\PDO $pdo) {
-        $pdo->exec('
-CREATE TABLE IF NOT EXISTS `sondage` (
-  `id_sondage` char(16) NOT NULL,
-  `commentaires` text,
-  `mail_admin` varchar(128) DEFAULT NULL,
-  `nom_admin` varchar(64) DEFAULT NULL,
-  `titre` text,
-  `id_sondage_admin` char(24) DEFAULT NULL,
-  `date_creation` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `date_fin` timestamp NULL DEFAULT NULL,
-  `format` varchar(2) DEFAULT NULL,
-  `mailsonde` tinyint(1) DEFAULT \'0\',
-  `statut` int(11) NOT NULL DEFAULT \'1\' COMMENT \'1 = actif ; 0 = inactif ; \',
-  UNIQUE KEY `id_sondage` (`id_sondage`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;');
-
-        $pdo->exec('
-CREATE TABLE IF NOT EXISTS `sujet_studs` (
-  `id_sondage` char(16) NOT NULL,
-  `sujet` text,
-  KEY `id_sondage` (`id_sondage`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;');
-
-        $pdo->exec('
-CREATE TABLE IF NOT EXISTS `comments` (
-  `id_comment` int(11) unsigned NOT NULL AUTO_INCREMENT,
-  `id_sondage` char(16) NOT NULL,
-  `comment` text NOT NULL,
-  `usercomment` text,
-  PRIMARY KEY (`id_comment`),
-  KEY `id_sondage` (`id_sondage`)
-) ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;');
-
-        $pdo->exec('
-CREATE TABLE IF NOT EXISTS `user_studs` (
-  `id_users` int(11) unsigned NOT NULL AUTO_INCREMENT,
-  `nom` varchar(64) NOT NULL,
-  `id_sondage` char(16) NOT NULL,
-  `reponses` text NOT NULL,
-  PRIMARY KEY (`id_users`),
-  KEY `id_sondage` (`id_sondage`)
-) ENGINE=InnoDB  DEFAULT CHARSET=utf8 ;');
-    }
-}
diff --git a/app/classes/Framadate/Migration/From_0_8_to_0_9_Migration.php b/app/classes/Framadate/Migration/From_0_8_to_0_9_Migration.php
deleted file mode 100644
index bb8ab7810b3fa68ac505a18628ea73e3fc28c753..0000000000000000000000000000000000000000
--- a/app/classes/Framadate/Migration/From_0_8_to_0_9_Migration.php
+++ /dev/null
@@ -1,292 +0,0 @@
-<?php
-/**
- * This software is governed by the CeCILL-B license. If a copy of this license
- * is not distributed with this file, you can obtain one at
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
- *
- * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
- * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
- *
- * =============================
- *
- * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
- * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
- *
- * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
- * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
- */
-namespace Framadate\Migration;
-
-use Framadate\Utils;
-
-/**
- * This class executes the aciton in database to migrate data from version 0.8 to 0.9.
- *
- * @package Framadate\Migration
- * @version 0.9
- */
-class From_0_8_to_0_9_Migration implements Migration {
-    function __construct() {
-    }
-
-    /**
-     * This method should describe in english what is the purpose of the migration class.
-     *
-     * @return string The description of the migration class
-     */
-    function description() {
-        return 'From 0.8 to 0.9';
-    }
-
-    /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the Migration should be executed.
-     */
-    function preCondition(\PDO $pdo) {
-        $stmt = $pdo->query('SHOW TABLES');
-        $tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
-
-        // Check if tables of v0.8 are presents
-        $diff = array_diff(['sondage', 'sujet_studs', 'comments', 'user_studs'], $tables);
-        return count($diff) === 0;
-    }
-
-    /**
-     * This method is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the execution succeeded
-     */
-    function execute(\PDO $pdo) {
-        $this->createPollTable($pdo);
-        $this->createCommentTable($pdo);
-        $this->createSlotTable($pdo);
-        $this->createVoteTable($pdo);
-
-        $pdo->beginTransaction();
-        $this->migrateFromSondageToPoll($pdo);
-        $this->migrateFromCommentsToComment($pdo);
-        $this->migrateFromSujetStudsToSlot($pdo);
-        $this->migrateFromUserStudsToVote($pdo);
-        $pdo->commit();
-
-        $this->dropOldTables($pdo);
-
-        return true;
-    }
-
-    private function createPollTable(\PDO $pdo) {
-        $pdo->exec('
-CREATE TABLE IF NOT EXISTS `' . Utils::table('poll') . '` (
-  `id`              CHAR(16)  NOT NULL,
-  `admin_id`        CHAR(24)  NOT NULL,
-  `title`           TEXT      NOT NULL,
-  `description`     TEXT,
-  `admin_name`      VARCHAR(64) DEFAULT NULL,
-  `admin_mail`      VARCHAR(128) DEFAULT NULL,
-  `creation_date`   TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `end_date`        TIMESTAMP NULL DEFAULT NULL,
-  `format`          VARCHAR(1) DEFAULT NULL,
-  `editable`        TINYINT(1) DEFAULT \'0\',
-  `receiveNewVotes` TINYINT(1) DEFAULT \'0\',
-  `active`          TINYINT(1) DEFAULT \'1\',
-  PRIMARY KEY (`id`)
-)
-  ENGINE = InnoDB
-  DEFAULT CHARSET = utf8');
-    }
-
-    private function migrateFromSondageToPoll(\PDO $pdo) {
-        $select = $pdo->query('
-SELECT
-    `id_sondage`,
-    `id_sondage_admin`,
-    `titre`,
-    `commentaires`,
-    `nom_admin`,
-    `mail_admin`,
-    `date_creation`,
-    `date_fin`,
-    SUBSTR(`format`, 1, 1) AS `format`,
-    CASE SUBSTR(`format`, 2, 1)
-    WHEN \'+\' THEN 1
-    ELSE 0 END             AS `editable`,
-    `mailsonde`,
-    CASE SUBSTR(`format`, 2, 1)
-    WHEN \'-\' THEN 0
-    ELSE 1 END             AS `active`
-  FROM sondage');
-
-        $insert = $pdo->prepare('
-INSERT INTO `' . Utils::table('poll') . '`
-(`id`, `admin_id`, `title`, `description`, `admin_name`, `admin_mail`, `creation_date`, `end_date`, `format`, `editable`, `receiveNewVotes`, `active`)
-VALUE (?,?,?,?,?,?,?,?,?,?,?,?)');
-
-        while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
-            $insert->execute([
-                $row->id_sondage,
-                $row->id_sondage_admin,
-                $this->unescape($row->titre),
-                $this->unescape($row->commentaires),
-                $this->unescape($row->nom_admin),
-                $this->unescape($row->mail_admin),
-                $row->date_creation,
-                $row->date_fin,
-                $row->format,
-                $row->editable,
-                $row->mailsonde,
-                $row->active
-            ]);
-        }
-    }
-
-    private function createSlotTable(\PDO $pdo) {
-        $pdo->exec('
-CREATE TABLE IF NOT EXISTS `' . Utils::table('slot') . '` (
-  `id`      INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
-  `poll_id` CHAR(16)         NOT NULL,
-  `title`   TEXT,
-  `moments` TEXT,
-  PRIMARY KEY (`id`),
-  KEY `poll_id` (`poll_id`)
-)
-  ENGINE = InnoDB
-  DEFAULT CHARSET = utf8');
-    }
-
-    private function migrateFromSujetStudsToSlot(\PDO $pdo) {
-        $stmt = $pdo->query('SELECT * FROM sujet_studs');
-        $sujets = $stmt->fetchAll();
-        $slots = [];
-
-        foreach ($sujets as $sujet) {
-            $newSlots = $this->transformSujetToSlot($sujet);
-            foreach ($newSlots as $newSlot) {
-                $slots[] = $newSlot;
-            }
-        }
-
-        $prepared = $pdo->prepare('INSERT INTO ' . Utils::table('slot') . ' (`poll_id`, `title`, `moments`) VALUE (?,?,?)');
-        foreach ($slots as $slot) {
-            $prepared->execute([
-                $slot->poll_id,
-                $this->unescape($slot->title),
-                !empty($slot->moments) ? $this->unescape($slot->moments) : null
-            ]);
-        }
-    }
-
-    private function createCommentTable(\PDO $pdo) {
-        $pdo->exec('
-CREATE TABLE IF NOT EXISTS `' . Utils::table('comment') . '` (
-  `id`      INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
-  `poll_id` CHAR(16)         NOT NULL,
-  `name`    TEXT,
-  `comment` TEXT             NOT NULL,
-  PRIMARY KEY (`id`),
-  KEY `poll_id` (`poll_id`)
-)
-  ENGINE = InnoDB
-  DEFAULT CHARSET = utf8');
-    }
-
-    private function migrateFromCommentsToComment(\PDO $pdo) {
-        $select = $pdo->query('
-SELECT
-    `id_sondage`,
-    `usercomment`,
-    `comment`
-  FROM `comments`');
-
-        $insert = $pdo->prepare('
-INSERT INTO `' . Utils::table('comment') . '` (`poll_id`, `name`, `comment`)
-VALUE (?,?,?)');
-
-        while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
-            $insert->execute([
-                $row->id_sondage,
-                $this->unescape($row->usercomment),
-                $this->unescape($row->comment)
-            ]);
-        }
-    }
-
-    private function createVoteTable(\PDO $pdo) {
-        $pdo->exec('
-CREATE TABLE IF NOT EXISTS `' . Utils::table('vote') . '` (
-  `id`      INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
-  `poll_id` CHAR(16)         NOT NULL,
-  `name`    VARCHAR(64)      NOT NULL,
-  `choices` TEXT             NOT NULL,
-  PRIMARY KEY (`id`),
-  KEY `poll_id` (`poll_id`)
-)
-  ENGINE = InnoDB
-  DEFAULT CHARSET = utf8');
-    }
-
-    private function migrateFromUserStudsToVote(\PDO $pdo) {
-        $select = $pdo->query('
-SELECT
-    `id_sondage`,
-    `nom`,
-    REPLACE(REPLACE(REPLACE(`reponses`, 1, \'X\'), 2, 1), \'X\', 2) reponses
-  FROM `user_studs`');
-
-        $insert = $pdo->prepare('
-INSERT INTO `' . Utils::table('vote') . '` (`poll_id`, `name`, `choices`)
-VALUE (?,?,?)');
-
-        while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
-            $insert->execute([
-                                 $row->id_sondage,
-                                 $this->unescape($row->nom),
-                                 $row->reponses
-                             ]);
-        }
-    }
-
-    private function transformSujetToSlot($sujet) {
-        $slots = [];
-        $ex = explode(',', $sujet->sujet);
-        $isDatePoll = strpos($sujet->sujet, '@');
-        $lastSlot = null;
-
-        foreach ($ex as $atomicSlot) {
-            if ($isDatePoll === false) { // Classic poll
-                $slot = new \stdClass();
-                $slot->poll_id = $sujet->id_sondage;
-                $slot->title = $atomicSlot;
-                $slots[] = $slot;
-            } else { // Date poll
-                $values = explode('@', $atomicSlot);
-                if ($lastSlot === null || $lastSlot->title !== $values[0]) {
-                    $lastSlot = new \stdClass();
-                    $lastSlot->poll_id = $sujet->id_sondage;
-                    $lastSlot->title = $values[0];
-                    $lastSlot->moments = count($values) === 2 ? $values[1] : '-';
-                    $slots[] = $lastSlot;
-                } else {
-                    $lastSlot->moments .= ',' . (count($values) === 2 ? $values[1] : '-');
-                }
-            }
-        }
-
-        return $slots;
-    }
-
-    private function dropOldTables(\PDO $pdo) {
-        $pdo->exec('DROP TABLE `comments`');
-        $pdo->exec('DROP TABLE `sujet_studs`');
-        $pdo->exec('DROP TABLE `user_studs`');
-        $pdo->exec('DROP TABLE `sondage`');
-    }
-
-    private function unescape($value) {
-        return stripslashes(html_entity_decode($value, ENT_QUOTES));
-    }
-}
diff --git a/app/classes/Framadate/Migration/Generate_uniqId_for_old_votes.php b/app/classes/Framadate/Migration/Generate_uniqId_for_old_votes.php
deleted file mode 100644
index fb814665025b984063712ce36a04958177a04635..0000000000000000000000000000000000000000
--- a/app/classes/Framadate/Migration/Generate_uniqId_for_old_votes.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-/**
- * This software is governed by the CeCILL-B license. If a copy of this license
- * is not distributed with this file, you can obtain one at
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
- *
- * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
- * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
- *
- * =============================
- *
- * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
- * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
- *
- * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
- * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
- */
-namespace Framadate\Migration;
-
-use Framadate\Security\Token;
-use Framadate\Utils;
-
-/**
- * This migration generate uniqId for all legacy votes.
- *
- * @package Framadate\Migration
- * @version 0.9
- */
-class Generate_uniqId_for_old_votes implements Migration {
-    function __construct() {
-    }
-
-    function description() {
-        return 'Generate "uniqId" in "vote" table for all legacy votes';
-    }
-
-    function preCondition(\PDO $pdo) {
-        $stmt = $pdo->query('SHOW TABLES');
-        $tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
-
-        // Check if tables of v0.9 are presents
-        $diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables);
-        return count($diff) === 0;
-    }
-
-    /**
-     * This methode is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the execution succeeded
-     */
-    function execute(\PDO $pdo) {
-        $pdo->beginTransaction();
-        $this->generateUniqIdsForEmptyOnes($pdo);
-        $pdo->commit();
-
-        return true;
-    }
-
-    private function generateUniqIdsForEmptyOnes($pdo) {
-        $select = $pdo->query('
-SELECT `id`
-  FROM `' . Utils::table('vote') . '`
- WHERE `uniqid` = \'\'');
-
-        $update = $pdo->prepare('
-UPDATE `' . Utils::table('vote') . '`
-   SET `uniqid` = :uniqid
- WHERE `id` = :id');
-
-        while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
-            $token = Token::getToken(16);
-            $update->execute([
-                'uniqid' => $token,
-                'id' => $row->id
-                             ]);
-        }
-    }
-}
diff --git a/app/classes/Framadate/Migration/Increase_pollId_size.php b/app/classes/Framadate/Migration/Increase_pollId_size.php
deleted file mode 100644
index 37eec25ce9d9e1ffe1c2a859abc6a2acc5bea2eb..0000000000000000000000000000000000000000
--- a/app/classes/Framadate/Migration/Increase_pollId_size.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-namespace Framadate\Migration;
-
-use Framadate\Utils;
-
-class Increase_pollId_size implements Migration {
-    function __construct() {
-    }
-
-    /**
-     * This method should describe in english what is the purpose of the migration class.
-     *
-     * @return string The description of the migration class
-     */
-    function description() {
-        return 'Increase the size of id column in poll table';
-    }
-
-    /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true if the Migration should be executed
-     */
-    function preCondition(\PDO $pdo) {
-        return true;
-    }
-
-    /**
-     * This methode is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true if the execution succeeded
-     */
-    function execute(\PDO $pdo) {
-        $this->alterCommentTable($pdo);
-        $this->alterPollTable($pdo);
-        $this->alterSlotTable($pdo);
-        $this->alterVoteTable($pdo);
-    }
-
-    private function alterCommentTable(\PDO $pdo) {
-        $pdo->exec('
-        ALTER TABLE `' . Utils::table('comment') . '`
-        CHANGE `poll_id` `poll_id` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;');
-    }
-
-    private function alterPollTable(\PDO $pdo) {
-        $pdo->exec('
-        ALTER TABLE `' . Utils::table('poll') . '`
-        CHANGE `id` `id` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;');
-    }
-
-    private function alterSlotTable(\PDO $pdo) {
-        $pdo->exec('
-        ALTER TABLE `' . Utils::table('slot') . '`
-        CHANGE `poll_id` `poll_id` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;');
-    }
-
-    private function alterVoteTable(\PDO $pdo) {
-        $pdo->exec('
-        ALTER TABLE `' . Utils::table('vote') . '`
-        CHANGE `poll_id` `poll_id` VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;');
-    }
-}
diff --git a/app/classes/Framadate/Migration/RPadVotes_from_0_8.php b/app/classes/Framadate/Migration/RPadVotes_from_0_8.php
deleted file mode 100644
index 52599eb5b4a40fe94eb753d19e25a9bd9aa9305b..0000000000000000000000000000000000000000
--- a/app/classes/Framadate/Migration/RPadVotes_from_0_8.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-/**
- * This software is governed by the CeCILL-B license. If a copy of this license
- * is not distributed with this file, you can obtain one at
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
- *
- * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
- * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
- *
- * =============================
- *
- * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
- * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
- * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
- *
- * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
- * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
- */
-namespace Framadate\Migration;
-
-use Framadate\Utils;
-
-/**
- * This migration RPad votes from version 0.8.
- * Because some votes does not have enough values for their poll.
- *
- * @package Framadate\Migration
- * @version 0.9
- */
-class RPadVotes_from_0_8 implements Migration {
-    function description() {
-        return 'RPad votes from version 0.8.';
-    }
-
-    function preCondition(\PDO $pdo) {
-        $stmt = $pdo->query('SHOW TABLES');
-        $tables = $stmt->fetchAll(\PDO::FETCH_COLUMN);
-
-        // Check if tables of v0.9 are presents
-        $diff = array_diff([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')], $tables);
-        return count($diff) === 0;
-    }
-
-    function execute(\PDO $pdo) {
-        $pdo->beginTransaction();
-        $this->rpadVotes($pdo);
-        $pdo->commit();
-
-        return true;
-    }
-
-    private function rpadVotes($pdo) {
-        $pdo->exec('UPDATE ' . Utils::table('vote') . ' fv
-INNER JOIN (
-	SELECT v.id, RPAD(v.choices, inn.slots_count, \'0\') new_choices
-	FROM ' . Utils::table('vote') . ' v
-	INNER JOIN
-		(SELECT s.poll_id, SUM(IFNULL(LENGTH(s.moments) - LENGTH(REPLACE(s.moments, \',\', \'\')) + 1, 1)) slots_count
-		FROM ' . Utils::table('slot') . ' s
-		GROUP BY s.poll_id
-		ORDER BY s.poll_id) inn ON inn.poll_id = v.poll_id
-	WHERE LENGTH(v.choices) != inn.slots_count
-) computed ON fv.id = computed.id
-SET fv.choices = computed.new_choices');
-    }
-}
\ No newline at end of file
diff --git a/app/classes/Framadate/Migrations/Version20150101000000.php b/app/classes/Framadate/Migrations/Version20150101000000.php
new file mode 100644
index 0000000000000000000000000000000000000000..afbf37923536d8a73b33e4bf4ccd2fdfac0c84b8
--- /dev/null
+++ b/app/classes/Framadate/Migrations/Version20150101000000.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
+
+/**
+ * Class From_0_0_to_0_8_Migration
+ *
+ * @package Framadate\Migration
+ * @version 0.8
+ */
+class Version20150101000000 extends AbstractMigration
+{
+    /**
+     * This method should describe in english what is the purpose of the migration class.
+     *
+     * @return string The description of the migration class
+     */
+    public function description()
+    {
+        return 'First installation of the Framadate application (v0.8)';
+    }
+
+    /**
+     * This method is called only one time in the migration page.
+     *
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @return void true is the execution succeeded
+     */
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema,'Framadate\Migration\From_0_0_to_0_8_Migration'), 'Migration has been executed in an earlier database migration system');
+        $sondage = $schema->createTable('sondage');
+        $sondage->addColumn('id_sondage', 'string');
+        $sondage->addColumn('commentaires', 'text');
+        $sondage->addColumn('mail_admin', 'string', ['notnull' => false]);
+        $sondage->addColumn('nom_admin', 'string', ['notnull' => false]);
+        $sondage->addColumn('titre', 'text');
+        $sondage->addColumn('id_sondage_admin', 'string', ['notnull' => false]);
+        $sondage->addColumn('date_creation', 'datetime', ['default' => (new \DateTime())->format('Y-m-d H:i:s')]);
+        $sondage->addColumn('date_fin', 'datetime', ['notnull' => false]);
+        $sondage->addColumn('format', 'string', ['notnull' => false]);
+        $sondage->addColumn('mailsonde', 'boolean', ['default' => false]);
+        $sondage->addColumn('statut', 'integer', ['default' => '1']);
+        $sondage->addUniqueIndex(['id_sondage'], 'sondage_index_id_sondage');
+
+        $sujetStuds = $schema->createTable('sujet_studs');
+        $sujetStuds->addColumn('id_sondage', 'string');
+        $sujetStuds->addColumn('sujet', 'text');
+        $sujetStuds->addIndex(['id_sondage'], 'sujet_studs_index_id_sondage');
+
+        $comments = $schema->createTable('comments');
+        $schema->createSequence('comments_seq');
+        $comments->addColumn('id_comment', 'integer', ['autoincrement' => true]);
+        $comments->addColumn('id_sondage', 'string');
+        $comments->addColumn('comment', 'text');
+        $comments->addColumn('usercomment', 'text', ['notnull' => false]);
+        $comments->addUniqueIndex(['id_comment'], 'comments_index_id_comment');
+        $comments->addIndex(['id_sondage'], 'comments_index_id_sondage');
+
+        $userStuds = $schema->createTable('user_studs');
+        $schema->createSequence('user_studs_seq');
+        $userStuds->addColumn('id_users', 'integer', ['autoincrement' => true]);
+        $userStuds->addColumn('nom', 'string');
+        $userStuds->addColumn('id_sondage', 'string');
+        $userStuds->addColumn('reponses', 'text');
+        $userStuds->addUniqueIndex(['id_users'], 'user_studs_index_id_users');
+        $userStuds->addIndex(['id_sondage'], 'user_studs_index_id_sondage');
+    }
+
+    public function down(Schema $schema)
+    {
+        $this->addSql('DROP TABLE sondage');
+        $this->addSql('DROP TABLE sujet_studs');
+        $this->addSql('DROP TABLE comments');
+        $this->addSql('DROP TABLE user_studs');
+    }
+}
diff --git a/app/classes/Framadate/Migrations/Version20150102000000.php b/app/classes/Framadate/Migrations/Version20150102000000.php
new file mode 100644
index 0000000000000000000000000000000000000000..46df4d9a7a0e96153c3e2434c9e356530543b2b1
--- /dev/null
+++ b/app/classes/Framadate/Migrations/Version20150102000000.php
@@ -0,0 +1,160 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
+use Framadate\Utils;
+
+/**
+ * This class executes the aciton in database to migrate data from version 0.8 to 0.9.
+ *
+ * @package Framadate\Migration
+ * @version 0.9
+ */
+class Version20150102000000 extends AbstractMigration
+{
+    /**
+     * This method should describe in english what is the purpose of the migration class.
+     *
+     * @return string The description of the migration class
+     */
+    public function description()
+    {
+        return 'From 0.8 to 0.9 first part';
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     */
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema,'Framadate\Migration\From_0_8_to_0_9_Migration'), 'Migration has been executed in an earlier database migration system');
+        foreach (['sondage', 'sujet_studs', 'comments', 'user_studs'] as $table) {
+            $this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
+        }
+
+        $this->createPollTable($schema);
+        $this->createCommentTable($schema);
+        $this->createSlotTable($schema);
+        $this->createVoteTable($schema);
+    }
+
+    public function down(Schema $schema)
+    {
+        $sondage = $schema->createTable('sondage');
+        $sondage->addColumn('id_sondage', 'string');
+        $sondage->addColumn('commentaires', 'text');
+        $sondage->addColumn('mail_admin', 'string', ['notnull' => false]);
+        $sondage->addColumn('nom_admin', 'string', ['notnull' => false]);
+        $sondage->addColumn('titre', 'text');
+        $sondage->addColumn('id_sondage_admin', 'string', ['notnull' => false]);
+        $sondage->addColumn('date_creation', 'datetime', ['default' => (new \DateTime())->format('Y-m-d H:i:s')]);
+        $sondage->addColumn('date_fin', 'datetime', ['notnull' => false]);
+        $sondage->addColumn('format', 'string', ['notnull' => false]);
+        $sondage->addColumn('mailsonde', 'boolean', ['default' => false]);
+        $sondage->addColumn('statut', 'integer', ['default' => '1']);
+        $sondage->addUniqueIndex(['id_sondage'], 'sondage_index_id_sondage');
+
+        $sujetStuds = $schema->createTable('sujet_studs');
+        $sujetStuds->addColumn('id_sondage', 'string');
+        $sujetStuds->addColumn('sujet', 'text');
+        $sujetStuds->addIndex(['id_sondage'], 'sujet_studs_index_id_sondage');
+
+        $comments = $schema->createTable('comments');
+        $schema->createSequence('comments_seq');
+        $comments->addColumn('id_comment', 'integer', ['autoincrement' => true]);
+        $comments->addColumn('id_sondage', 'string');
+        $comments->addColumn('comment', 'text');
+        $comments->addColumn('usercomment', 'text', ['notnull' => false]);
+        $comments->addUniqueIndex(['id_comment'], 'comments_index_id_comment');
+        $comments->addIndex(['id_sondage'], 'comments_index_id_sondage');
+
+        $userStuds = $schema->createTable('user_studs');
+        $schema->createSequence('user_studs_seq');
+        $userStuds->addColumn('id_users', 'integer', ['autoincrement' => true]);
+        $userStuds->addColumn('nom', 'string');
+        $userStuds->addColumn('id_sondage', 'string');
+        $userStuds->addColumn('reponses', 'text');
+        $userStuds->addUniqueIndex(['id_users'], 'user_studs_index_id_users');
+        $userStuds->addIndex(['id_sondage'], 'user_studs_index_id_sondage');
+
+        $schema->dropTable(Utils::table('poll'));
+        $schema->dropTable(Utils::table('comment'));
+        $schema->dropTable(Utils::table('vote'));
+        $schema->dropTable(Utils::table('slot'));
+    }
+
+    private function createPollTable(Schema $schema)
+    {
+        $poll = $schema->createTable(Utils::table('poll'));
+        $poll->addColumn('id', 'string');
+        $poll->addColumn('admin_id', 'string');
+        $poll->addColumn('title', 'text');
+        $poll->addColumn('description', 'text', ['notnull' => false]);
+        $poll->addColumn('admin_name', 'string');
+        $poll->addColumn('admin_mail', 'string', ['notnull' => false]);
+        $poll->addColumn('creation_date', 'datetime', ['default' => (new \DateTime())->format('Y-m-d H:i:s')]);
+        $poll->addColumn('end_date', 'datetime', ['notnull' => false]);
+        $poll->addColumn('format', 'string', ['default' => null, 'notnull' => false]);
+        $poll->addColumn('editable', 'integer', ['default' => 0]);
+        $poll->addColumn('receiveNewVotes', 'boolean', ['default' => false]);
+        $poll->addColumn('active', 'boolean', ['default' => true]);
+        $poll->addUniqueIndex(['id'], 'poll_index_id');
+    }
+
+    private function createSlotTable(Schema $schema)
+    {
+        $slot = $schema->createTable(Utils::table('slot'));
+        $schema->createSequence('slot_seq');
+        $slot->addColumn('id', 'integer', ['autoincrement' => true]);
+        $slot->addColumn('poll_id', 'string');
+        $slot->addColumn('title', 'text');
+        $slot->addColumn('moments', 'text', ['notnull' => false]);
+        $slot->addUniqueIndex(['id'], 'slot_index_id');
+        $slot->addIndex(['poll_id'], 'slot_index_poll_id');
+    }
+
+    private function createCommentTable(Schema $schema)
+    {
+        $comment = $schema->createTable(Utils::table('comment'));
+        $schema->createSequence('comment_seq');
+        $comment->addColumn('id', 'integer', ['autoincrement' => true]);
+        $comment->addColumn('poll_id', 'string');
+        $comment->addColumn('name', 'text', ['notnull' => false]);
+        $comment->addColumn('comment', 'text');
+        $comment->addUniqueIndex(['id'], 'comment_index_id');
+        $comment->addIndex(['poll_id'], 'comment_index_poll_id');
+    }
+
+    private function createVoteTable(Schema $schema)
+    {
+        $vote = $schema->createTable(Utils::table('vote'));
+        $schema->createSequence('vote_seq');
+        $vote->addColumn('id', 'integer', ['autoincrement' => true]);
+        $vote->addColumn('poll_id', 'string');
+        $vote->addColumn('name', 'string');
+        $vote->addColumn('choices', 'string');
+        $vote->addUniqueIndex(['id'], 'vote_index_id');
+        $vote->addIndex(['poll_id'], 'vote_index_poll_id');
+    }
+}
diff --git a/app/classes/Framadate/Migrations/Version20150102100000.php b/app/classes/Framadate/Migrations/Version20150102100000.php
new file mode 100644
index 0000000000000000000000000000000000000000..ae8ecfeb079fee7319a0267a53554d283d1d8334
--- /dev/null
+++ b/app/classes/Framadate/Migrations/Version20150102100000.php
@@ -0,0 +1,263 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
+use Framadate\Utils;
+
+/**
+ * This class executes the aciton in database to migrate data from version 0.8 to 0.9.
+ *
+ * @package Framadate\Migration
+ * @version 0.9
+ */
+class Version20150102100000 extends AbstractMigration
+{
+    /**
+     * This method should describe in english what is the purpose of the migration class.
+     *
+     * @return string The description of the migration class
+     */
+    public function description()
+    {
+        return 'From 0.8 to 0.9 second part';
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     */
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema,'Framadate\Migration\From_0_8_to_0_9_Migration'), 'Migration has been executed in an earlier database migration system');
+        foreach ([Utils::table('poll'), Utils::table('comment'), Utils::table('slot'), Utils::table('vote')] as $table) {
+            $this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
+        }
+
+        $this->migrateFromSondageToPoll();
+        $this->migrateFromCommentsToComment();
+        $this->migrateFromSujetStudsToSlot();
+        //$this->migrateFromUserStudsToVote();
+
+        $this->dropOldTables($schema);
+    }
+
+    public function down(Schema $schema)
+    {
+        $sondage = $schema->createTable('sondage');
+        $sondage->addColumn('id_sondage', 'string');
+        $sondage->addColumn('commentaires', 'text');
+        $sondage->addColumn('mail_admin', 'string', ['notnull' => false]);
+        $sondage->addColumn('nom_admin', 'string', ['notnull' => false]);
+        $sondage->addColumn('titre', 'text');
+        $sondage->addColumn('id_sondage_admin', 'string', ['notnull' => false]);
+        $sondage->addColumn('date_creation', 'datetime', ['default' => (new \DateTime())->format('Y-m-d H:i:s')]);
+        $sondage->addColumn('date_fin', 'datetime', ['notnull' => false]);
+        $sondage->addColumn('format', 'string', ['notnull' => false]);
+        $sondage->addColumn('mailsonde', 'boolean', ['default' => false]);
+        $sondage->addColumn('statut', 'integer', ['default' => '1']);
+        $sondage->addUniqueIndex(['id_sondage'], 'sondage_index_id_sondage');
+
+        $sujetStuds = $schema->createTable('sujet_studs');
+        $sujetStuds->addColumn('id_sondage', 'string');
+        $sujetStuds->addColumn('sujet', 'text');
+        $sujetStuds->addIndex(['id_sondage'], 'sujet_studs_index_id_sondage');
+
+        $comments = $schema->createTable('comments');
+        $schema->createSequence('comments_seq');
+        $comments->addColumn('id_comment', 'integer', ['autoincrement' => true]);
+        $comments->addColumn('id_sondage', 'string');
+        $comments->addColumn('comment', 'text');
+        $comments->addColumn('usercomment', 'text', ['notnull' => false]);
+        $comments->addUniqueIndex(['id_comment'], 'comments_index_id_comment');
+        $comments->addIndex(['id_sondage'], 'comments_index_id_sondage');
+
+        $userStuds = $schema->createTable('user_studs');
+        $schema->createSequence('user_studs_seq');
+        $userStuds->addColumn('id_users', 'integer', ['autoincrement' => true]);
+        $userStuds->addColumn('nom', 'string');
+        $userStuds->addColumn('id_sondage', 'string');
+        $userStuds->addColumn('reponses', 'text');
+        $userStuds->addUniqueIndex(['id_users'], 'user_studs_index_id_users');
+        $userStuds->addIndex(['id_sondage'], 'user_studs_index_id_sondage');
+
+        $schema->dropTable(Utils::table('poll'));
+        $schema->dropTable(Utils::table('comment'));
+        $schema->dropTable(Utils::table('vote'));
+        $schema->dropTable(Utils::table('slot'));
+    }
+
+    private function migrateFromSondageToPoll()
+    {
+        $select = $this->connection->query('
+SELECT
+    id_sondage,
+    id_sondage_admin,
+    titre,
+    commentaires,
+    nom_admin,
+    mail_admin,
+    date_creation,
+    date_fin,
+    SUBSTR(format, 1, 1) AS format,
+    CASE SUBSTR(format, 2, 1)
+    WHEN \'+\' THEN 1
+    ELSE 0 END             AS editable,
+    mailsonde,
+    CASE SUBSTR(format, 2, 1)
+    WHEN \'-\' THEN 0
+    ELSE 1 END             AS active
+  FROM sondage');
+
+        $insert = $this->connection->prepare('
+INSERT INTO ' . Utils::table('poll') . '
+(id, admin_id, title, description, admin_name, admin_mail, creation_date, end_date, format, editable, receiveNewVotes, active)
+VALUES (?,?,?,?,?,?,?,?,?,?,?,?)');
+
+        while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
+            $insert->execute([
+                $row->id_sondage,
+                $row->id_sondage_admin,
+                $this->unescape($row->titre),
+                $this->unescape($row->commentaires),
+                $this->unescape($row->nom_admin),
+                $this->unescape($row->mail_admin),
+                $row->date_creation,
+                $row->date_fin,
+                $row->format,
+                $row->editable,
+                $row->mailsonde,
+                $row->active
+            ]);
+        }
+    }
+
+    private function migrateFromSujetStudsToSlot()
+    {
+        $stmt = $this->connection->query('SELECT * FROM sujet_studs');
+        $sujets = $stmt->fetchAll();
+        $slots = [];
+
+        foreach ($sujets as $sujet) {
+            $newSlots = $this->transformSujetToSlot($sujet);
+            foreach ($newSlots as $newSlot) {
+                $slots[] = $newSlot;
+            }
+        }
+
+        $prepared = $this->connection->prepare('INSERT INTO ' . Utils::table('slot') . ' (poll_id, title, moments) VALUES (?,?,?)');
+        foreach ($slots as $slot) {
+            $prepared->execute([
+                $slot->poll_id,
+                $this->unescape($slot->title),
+                !empty($slot->moments) ? $this->unescape($slot->moments) : null
+            ]);
+        }
+    }
+
+    private function migrateFromCommentsToComment()
+    {
+        $select = $this->connection->query('
+SELECT
+    id_sondage,
+    usercomment,
+    comment
+  FROM comments');
+
+        $insert = $this->connection->prepare('
+INSERT INTO ' . Utils::table('comment') . ' (poll_id, name, comment)
+VALUES (?,?,?)');
+
+        while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
+            $insert->execute([
+                $row->id_sondage,
+                $this->unescape($row->usercomment),
+                $this->unescape($row->comment)
+            ]);
+        }
+    }
+
+    private function migrateFromUserStudsToVote()
+    {
+        $select = $this->connection->query('
+SELECT
+    id_sondage,
+    nom,
+    REPLACE(REPLACE(REPLACE(reponses, 1, \'X\'), 2, 1), \'X\', 2) reponses
+  FROM user_studs');
+
+        $insert = $this->connection->prepare('
+INSERT INTO ' . Utils::table('vote') . ' (poll_id, name, choices)
+VALUES (?,?,?)');
+
+        while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
+            $insert->execute([
+                                 $row->id_sondage,
+                                 $this->unescape($row->nom),
+                                 $row->reponses
+                             ]);
+        }
+    }
+
+    private function transformSujetToSlot($sujet)
+    {
+        $slots = [];
+        $ex = explode(',', $sujet->sujet);
+        $isDatePoll = strpos($sujet->sujet, '@');
+        $lastSlot = null;
+
+        foreach ($ex as $atomicSlot) {
+            if ($isDatePoll === false) { // Classic poll
+                $slot = new \stdClass();
+                $slot->poll_id = $sujet->id_sondage;
+                $slot->title = $atomicSlot;
+                $slots[] = $slot;
+            } else { // Date poll
+                $values = explode('@', $atomicSlot);
+                if ($lastSlot === null || $lastSlot->title !== $values[0]) {
+                    $lastSlot = new \stdClass();
+                    $lastSlot->poll_id = $sujet->id_sondage;
+                    $lastSlot->title = $values[0];
+                    $lastSlot->moments = count($values) === 2 ? $values[1] : '-';
+                    $slots[] = $lastSlot;
+                } else {
+                    $lastSlot->moments .= ',' . (count($values) === 2 ? $values[1] : '-');
+                }
+            }
+        }
+
+        return $slots;
+    }
+
+    private function dropOldTables(Schema $schema)
+    {
+        $schema->dropTable('comments');
+        $schema->dropTable('sujet_studs');
+        $schema->dropTable('user_studs');
+        $schema->dropTable('sondage');
+    }
+
+    private function unescape($value)
+    {
+        return stripslashes(html_entity_decode($value, ENT_QUOTES));
+    }
+}
diff --git a/app/classes/Framadate/Migrations/Version20150117000000.php b/app/classes/Framadate/Migrations/Version20150117000000.php
new file mode 100644
index 0000000000000000000000000000000000000000..883d85cd9a82cd062360cd792d552da5974182eb
--- /dev/null
+++ b/app/classes/Framadate/Migrations/Version20150117000000.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
+use Framadate\Utils;
+
+/**
+ * This migration adds the field receiveNewComments on the poll table.
+ *
+ * @package Framadate\Migration
+ * @version 0.9
+ */
+class Version20150117000000 extends AbstractMigration
+{
+    /**
+     * This method should describe in english what is the purpose of the migration class.
+     *
+     * @return string The description of the migration class
+     */
+    public function description()
+    {
+        return 'Add column "receiveNewComments" for version 0.9';
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @throws \Doctrine\DBAL\DBALException
+     */
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema,'Framadate\Migration\AddColumn_receiveNewComments_For_0_9'), 'Migration has been executed in an earlier database migration system');
+        foreach ([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')] as $table) {
+            $this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
+        }
+        $pollTable = $schema->getTable(Utils::table('poll'));
+        $this->skipIf($pollTable->hasColumn('receiveNewComments'), 'Column receiveNewComments already exists');
+
+        $pollTable->addColumn('receiveNewComments', 'boolean', ['default' => false]);
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     */
+    public function down(Schema $schema)
+    {
+        $pollTable = $schema->getTable(Utils::table('poll'));
+        $pollTable->dropColumn('receiveNewComments');
+    }
+}
diff --git a/app/classes/Framadate/Migrations/Version20150402000000.php b/app/classes/Framadate/Migrations/Version20150402000000.php
new file mode 100644
index 0000000000000000000000000000000000000000..08f5f187aef67c13027157569bc15ab8ff4de0ca
--- /dev/null
+++ b/app/classes/Framadate/Migrations/Version20150402000000.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
+use Framadate\Utils;
+
+/**
+ * This migration adds the field uniqId on the vote table.
+ *
+ * @package Framadate\Migration
+ * @version 0.9
+ */
+class Version20150402000000 extends AbstractMigration
+{
+    private $indexUniqIdName = 'IDX_vote_uniqId';
+
+    /**
+     * This method should describe in english what is the purpose of the migration class.
+     *
+     * @return string The description of the migration class
+     */
+    public function description()
+    {
+        return 'Add column "uniqId" in table "vote" for version 0.9';
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @throws \Doctrine\DBAL\DBALException
+     */
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\AddColumn_uniqId_In_vote_For_0_9'), 'Migration has been executed in an earlier database migration system');
+        foreach ([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')] as $table) {
+            $this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
+        }
+        $voteTable = $schema->getTable(Utils::table('vote'));
+
+        $this->skipIf($voteTable->hasColumn('uniqId'), 'Column uniqId already existing');
+
+        $voteTable->addColumn('uniqId', 'string', ['length' => 16]);
+        $voteTable->addIndex(['uniqId'], $this->indexUniqIdName);
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     */
+    public function down(Schema $schema)
+    {
+        $voteTable = $schema->getTable(Utils::table('vote'));
+
+        $voteTable->dropIndex($this->indexUniqIdName);
+        $voteTable->dropColumn('uniqId');
+    }
+}
diff --git a/app/classes/Framadate/Migrations/Version20150405000000.php b/app/classes/Framadate/Migrations/Version20150405000000.php
new file mode 100644
index 0000000000000000000000000000000000000000..d03b624a24c9c2077c1eda1537b8dbe213242fe7
--- /dev/null
+++ b/app/classes/Framadate/Migrations/Version20150405000000.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
+use Framadate\Utils;
+
+/**
+ * This migration adds the field hidden on the poll table.
+ *
+ * @package Framadate\Migration
+ * @version 0.9
+ */
+class Version20150405000000 extends AbstractMigration
+{
+    /**
+     * This method should describe in english what is the purpose of the migration class.
+     *
+     * @return string The description of the migration class
+     */
+    public function description()
+    {
+        return 'Add column "hidden" in table "vote" for version 0.9';
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @throws \Doctrine\DBAL\DBALException
+     */
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\AddColumn_hidden_In_poll_For_0_9'), 'Migration has been executed in an earlier database migration system');
+        foreach ([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')] as $table) {
+            $this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
+        }
+        $pollTable = $schema->getTable(Utils::table('poll'));
+
+        $this->skipIf($pollTable->hasColumn('hidden'), 'Column hidden already existing in table poll');
+
+        $pollTable->addColumn('hidden', 'boolean', ['default' => false, 'notnull' => true]);
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     */
+    public function down(Schema $schema)
+    {
+        $pollTable = $schema->getTable(Utils::table('poll'));
+
+        $pollTable->dropColumn('hidden');
+    }
+}
diff --git a/app/classes/Framadate/Migrations/Version20150624000000.php b/app/classes/Framadate/Migrations/Version20150624000000.php
new file mode 100644
index 0000000000000000000000000000000000000000..a71e056532afccf6595977ad6569aeb1faed78b9
--- /dev/null
+++ b/app/classes/Framadate/Migrations/Version20150624000000.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
+use Framadate\Security\Token;
+use Framadate\Utils;
+
+/**
+ * This migration generate uniqId for all legacy votes.
+ *
+ * @package Framadate\Migration
+ * @version 0.9
+ */
+class Version20150624000000 extends AbstractMigration
+{
+    public function description()
+    {
+        return 'Generate "uniqId" in "vote" table for all legacy votes';
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     */
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\Generate_uniqId_for_old_votes'), 'Migration has been executed in an earlier database migration system');
+        foreach ([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table('comment')] as $table) {
+            $this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
+        }
+
+        $this->connection->beginTransaction();
+
+        $select = $this->connection->query('
+SELECT id
+  FROM ' . Utils::table('vote') . '
+ WHERE uniqid = \'\'');
+
+        $update = $this->connection->prepare('
+UPDATE ' . Utils::table('vote') . '
+   SET uniqid = :uniqid
+ WHERE id = :id');
+
+        while ($row = $select->fetch(\PDO::FETCH_OBJ)) {
+            $token = Token::getToken(16);
+            $update->execute([
+                                 'uniqid' => $token,
+                                 'id' => $row->id
+                             ]);
+        }
+
+        $this->connection->commit();
+    }
+
+    public function down(Schema $schema)
+    {
+        // TODO: Implement down() method.
+    }
+}
diff --git a/app/classes/Framadate/Migrations/Version20150918000000.php b/app/classes/Framadate/Migrations/Version20150918000000.php
new file mode 100644
index 0000000000000000000000000000000000000000..5b1976811c67e1392f937ee322810da568385580
--- /dev/null
+++ b/app/classes/Framadate/Migrations/Version20150918000000.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Rapha�l DROZ
+ * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est r�gi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Rapha�l DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
+use Framadate\Utils;
+
+/**
+ * This migration RPad votes from version 0.8.
+ * Because some votes does not have enough values for their poll.
+ *
+ * @package Framadate\Migration
+ * @version 0.9
+ */
+class Version20150918000000 extends AbstractMigration
+{
+    public function description()
+    {
+        return 'RPad votes from version 0.8.';
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     */
+    public function up(Schema $schema)
+    {
+        $this->skipIf(
+            $this->legacyCheck($schema, 'Framadate\Migration\RPadVotes_from_0_8'),
+            'Migration has been executed in an earlier database migration system'
+        );
+        foreach ([Utils::table('poll'), Utils::table('slot'), Utils::table('vote'), Utils::table(
+            'comment'
+        )] as $table) {
+            $this->skipIf(!$schema->hasTable($table), 'Missing table ' . $table);
+        }
+
+        $driver_name = $this->connection->getDatabasePlatform()->getName();
+        switch ($driver_name) {
+            case 'mysql':
+                $this->addSql(
+                    'UPDATE ' . Utils::table('vote') . ' fv
+INNER JOIN (
+	SELECT v.id, RPAD(v.choices, inn.slots_count, \'0\') new_choices
+	FROM ' . Utils::table('vote') . ' v
+	INNER JOIN
+		(SELECT s.poll_id, SUM(IFNULL(LENGTH(s.moments) - LENGTH(REPLACE(s.moments, \',\', \'\')) + 1, 1)) slots_count
+		FROM ' . Utils::table('slot') . ' s
+		GROUP BY s.poll_id
+		ORDER BY s.poll_id) inn ON inn.poll_id = v.poll_id
+	WHERE LENGTH(v.choices) != inn.slots_count
+) computed ON fv.id = computed.id
+SET fv.choices = computed.new_choices'
+                );
+                break;
+            case 'postgresql':
+                $this->addSql(
+                    "UPDATE " . Utils::table('vote') . " fv
+                    SET choices = computed.new_choices
+FROM (
+	SELECT v.id, RPAD(v.choices::text, inn.slots_count::int, '0') new_choices
+	FROM " . Utils::table('vote') . " v
+	INNER JOIN
+		(SELECT s.poll_id, SUM(coalesce(LENGTH(s.moments) - LENGTH(REPLACE(s.moments, ',', '')) + 1, 1)) slots_count
+		FROM " . Utils::table('slot') . " s
+		GROUP BY s.poll_id
+		ORDER BY s.poll_id) inn ON inn.poll_id = v.poll_id
+	WHERE LENGTH(v.choices) != inn.slots_count
+) computed WHERE fv.id = computed.id"
+                );
+                break;
+            default:
+                $this->skipIf(true, "Not on MySQL or PostgreSQL");
+                break;
+        }
+    }
+
+    public function down(Schema $schema)
+    {
+        // TODO: Implement down() method.
+    }
+}
diff --git a/app/classes/Framadate/Migration/Alter_Comment_table_for_name_length.php b/app/classes/Framadate/Migrations/Version20151012075900.php
similarity index 50%
rename from app/classes/Framadate/Migration/Alter_Comment_table_for_name_length.php
rename to app/classes/Framadate/Migrations/Version20151012075900.php
index 1844c811f7be7b15aa72b122a6fd1800d82ea2c9..e31ad619a8a5f6afb6bc161c741305304d872869 100644
--- a/app/classes/Framadate/Migration/Alter_Comment_table_for_name_length.php
+++ b/app/classes/Framadate/Migrations/Version20151012075900.php
@@ -16,8 +16,11 @@
  * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
  * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
  */
-namespace Framadate\Migration;
+namespace DoctrineMigrations;
 
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\DBAL\Types\Type;
+use Framadate\AbstractMigration;
 use Framadate\Utils;
 
 /**
@@ -26,45 +29,43 @@ use Framadate\Utils;
  * @package Framadate\Migration
  * @version 1.0
  */
-class Alter_Comment_table_for_name_length implements Migration {
-    function __construct() {
-    }
-
+class Version20151012075900 extends AbstractMigration
+{
     /**
      * This method should describe in english what is the purpose of the migration class.
      *
      * @return string The description of the migration class
      */
-    function description() {
+    public function description()
+    {
         return 'Alter the comment table to set a length to the name column.';
     }
 
     /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the Migration should be executed.
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
      */
-    function preCondition(\PDO $pdo) {
-        return true;
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\Alter_Comment_table_for_name_length'), 'Migration has been executed in an earlier database migration system');
+        $commentTable = $schema->getTable(Utils::table('comment'));
+
+        $commentTable->changeColumn('name', ['default' => null, 'notnull' => false]);
+
+        $commentTable->changeColumn('name', ['type' => Type::getType('string'), 'length' => 64, 'notnull' => true]);
     }
 
     /**
-     * This methode is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the execution succeeded
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @throws \Doctrine\DBAL\DBALException
      */
-    function execute(\PDO $pdo) {
-        $this->alterCommentTable($pdo);
-
-        return true;
-    }
+    public function down(Schema $schema)
+    {
+        $commentTable = $schema->getTable(Utils::table('comment'));
 
-    private function alterCommentTable(\PDO $pdo) {
-        $pdo->exec('
-        ALTER TABLE `' . Utils::table('comment') . '`
-        CHANGE `name` `name` VARCHAR( 64 ) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL ;');
+        $commentTable->changeColumn('name', ['type' => Type::getType('string')]);
     }
 }
diff --git a/app/classes/Framadate/Migration/Alter_Comment_table_adding_date.php b/app/classes/Framadate/Migrations/Version20151012082600.php
similarity index 53%
rename from app/classes/Framadate/Migration/Alter_Comment_table_adding_date.php
rename to app/classes/Framadate/Migrations/Version20151012082600.php
index afc57a9471fe06ca05bba687de2a911e5e3b9f81..919b0ba8012beb0317a2f1dffe96ea6f19cb0f2f 100644
--- a/app/classes/Framadate/Migration/Alter_Comment_table_adding_date.php
+++ b/app/classes/Framadate/Migrations/Version20151012082600.php
@@ -16,8 +16,10 @@
  * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
  * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
  */
-namespace Framadate\Migration;
+namespace DoctrineMigrations;
 
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
 use Framadate\Utils;
 
 /**
@@ -26,45 +28,42 @@ use Framadate\Utils;
  * @package Framadate\Migration
  * @version 1.0
  */
-class Alter_Comment_table_adding_date implements Migration {
-    function __construct() {
-    }
-
+class Version20151012082600 extends AbstractMigration
+{
     /**
      * This method should describe in english what is the purpose of the migration class.
      *
      * @return string The description of the migration class
      */
-    function description() {
+    public function description()
+    {
         return 'Alter the comment table to add a date column.';
     }
 
     /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the Migration should be executed.
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @throws \Doctrine\DBAL\DBALException
      */
-    function preCondition(\PDO $pdo) {
-        return true;
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\Alter_Comment_table_adding_date'), 'Migration has been executed in an earlier database migration system');
+        $commentTable = $schema->getTable(Utils::table('comment'));
+
+        $this->skipIf($commentTable->hasColumn('date'), 'Column date in comment table already exists');
+
+        $commentTable->addColumn('date', 'datetime', ['default' => 0]);
     }
 
     /**
-     * This methode is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the execution succeeded
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
      */
-    function execute(\PDO $pdo) {
-        $this->alterCommentTable($pdo);
-
-        return true;
-    }
+    public function down(Schema $schema)
+    {
+        $commentTable = $schema->getTable(Utils::table('comment'));
 
-    private function alterCommentTable(\PDO $pdo) {
-        $pdo->exec('
-        ALTER TABLE `' . Utils::table('comment') . '`
-        ADD `date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ;');
+        $commentTable->dropColumn('comment');
     }
 }
diff --git a/app/classes/Framadate/Migrations/Version20151028000000.php b/app/classes/Framadate/Migrations/Version20151028000000.php
new file mode 100644
index 0000000000000000000000000000000000000000..af9574593bbf899098e4d0b0f5cba74dfb617c77
--- /dev/null
+++ b/app/classes/Framadate/Migrations/Version20151028000000.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
+use Framadate\Utils;
+
+/**
+ * This migration adds the fields password_hash and results_publicly_visible on the poll table.
+ *
+ * @package Framadate\Migration
+ * @version 0.9
+ */
+class Version20151028000000 extends AbstractMigration
+{
+    /**
+     * This method should describe in english what is the purpose of the migration class.
+     *
+     * @return string The description of the migration class
+     */
+    public function description()
+    {
+        return 'Add columns "password_hash" and "results_publicly_visible" in table "vote" for version 0.9';
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @throws \Doctrine\DBAL\DBALException
+     */
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9'), 'Migration has been executed in an earlier database migration system');
+        $pollTable = $schema->getTable(Utils::table('poll'));
+
+        $this->skipIf($pollTable->hasColumn('password_hash'), 'Column password_hash in table poll already exists');
+        $this->skipIf($pollTable->hasColumn('results_publicly_visible'), 'Column results_publicly_visible in table poll already exists');
+
+        $pollTable->addColumn('password_hash', 'string', ['notnull' => false]);
+        $pollTable->addColumn('results_publicly_visible', 'boolean', ['notnull' => false]);
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     */
+    public function down(Schema $schema)
+    {
+        $pollTable = $schema->getTable(Utils::table('poll'));
+
+        $pollTable->dropColumn('password_hash');
+        $pollTable->dropColumn('results_publicly_visible');
+    }
+}
diff --git a/app/classes/Framadate/Migrations/Version20151205000000.php b/app/classes/Framadate/Migrations/Version20151205000000.php
new file mode 100644
index 0000000000000000000000000000000000000000..8b2f5b37ae981086188219df337c309fcb7187f0
--- /dev/null
+++ b/app/classes/Framadate/Migrations/Version20151205000000.php
@@ -0,0 +1,51 @@
+<?php
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Schema\Schema;
+use Doctrine\DBAL\Types\Type;
+use Framadate\AbstractMigration;
+use Framadate\Utils;
+
+class Version20151205000000 extends AbstractMigration
+{
+    /**
+     * This method should describe in english what is the purpose of the migration class.
+     *
+     * @return string The description of the migration class
+     */
+    public function description()
+    {
+        return 'Increase the size of id column in poll table';
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @throws \Doctrine\DBAL\DBALException
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     */
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\Increase_pollId_size'), 'Migration has been executed in an earlier database migration system');
+        $commentTable = $schema->getTable(Utils::table('comment'));
+
+        $commentTable->changeColumn('poll_id', ['type' => Type::getType('string'), 'length' => 64, 'notnull' => true]);
+
+        $pollTable = $schema->getTable(Utils::table('poll'));
+
+        $pollTable->changeColumn('id', ['type' => Type::getType('string'), 'length' => 64, 'notnull' => true]);
+
+        $slotTable = $schema->getTable(Utils::table('slot'));
+
+        $slotTable->changeColumn('poll_id', ['type' => Type::getType('string'), 'length' => 64, 'notnull' => true]);
+
+        $voteTable = $schema->getTable(Utils::table('vote'));
+
+        $voteTable->changeColumn('poll_id', ['type' => Type::getType('string'), 'length' => 64, 'notnull' => true]);
+    }
+
+    public function down(Schema $schema)
+    {
+        // TODO: Implement down() method.
+    }
+}
diff --git a/app/classes/Framadate/Migration/AddColumn_ValueMax_In_poll_For_1_1.php b/app/classes/Framadate/Migrations/Version20180220000000.php
similarity index 55%
rename from app/classes/Framadate/Migration/AddColumn_ValueMax_In_poll_For_1_1.php
rename to app/classes/Framadate/Migrations/Version20180220000000.php
index 8b1caa22b9ac7b601e70855efc6278e7acdd2fdd..334a4d1c2c626375b5fa3398dc7a8b4cbbdec8f2 100644
--- a/app/classes/Framadate/Migration/AddColumn_ValueMax_In_poll_For_1_1.php
+++ b/app/classes/Framadate/Migrations/Version20180220000000.php
@@ -16,8 +16,10 @@
  * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
  * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
  */
-namespace Framadate\Migration;
+namespace DoctrineMigrations;
 
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
 use Framadate\Utils;
 
 /**
@@ -26,45 +28,38 @@ use Framadate\Utils;
  * @package Framadate\Migration
  * @version 0.9
  */
-class AddColumn_ValueMax_In_poll_For_1_1 implements Migration {
-    function __construct() {
-    }
-
+class Version20180220000000 extends AbstractMigration
+{
     /**
      * This method should describe in english what is the purpose of the migration class.
      *
      * @return string The description of the migration class
      */
-    function description() {
+    public function description()
+    {
         return 'Add column "ValueMax" in table "vote" for version 0.9';
     }
 
     /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the Migration should be executed.
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\DBALException
      */
-    function preCondition(\PDO $pdo) {
-        return true;
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\AddColumn_ValueMax_In_poll_For_1_1'), 'Migration has been executed in an earlier database migration system');
+        $pollTable = $schema->getTable(Utils::table('poll'));
+        $pollTable->addColumn('ValueMax', 'smallint', ['default' => null, 'notnull' => false]);
     }
 
     /**
-     * This method is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the execution succeeded
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
      */
-    function execute(\PDO $pdo) {
-        $this->alterPollTable($pdo);
-
-        return true;
-    }
-
-    private function alterPollTable(\PDO $pdo) {
-        $pdo->exec('
-        ALTER TABLE `' . Utils::table('poll') . '`
-        ADD `ValueMax` TINYINT NULL;');
+    public function down(Schema $schema)
+    {
+        $pollTable = $schema->getTable(Utils::table('poll'));
+        $pollTable->dropColumn('ValueMax');
     }
 }
diff --git a/app/classes/Framadate/Migrations/Version20180411000000.php b/app/classes/Framadate/Migrations/Version20180411000000.php
new file mode 100644
index 0000000000000000000000000000000000000000..59dad11caed37c06c855301df8a490bcd88adefa
--- /dev/null
+++ b/app/classes/Framadate/Migrations/Version20180411000000.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+namespace DoctrineMigrations;
+
+use Doctrine\DBAL\Connection;
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
+use Framadate\Utils;
+
+/**
+ * This migration sets Poll.end_date to NULL by default
+ *
+ * @package Framadate\Migration
+ * @version 1.1
+ */
+class Version20180411000000 extends AbstractMigration
+{
+    /**
+     * This method should describe in english what is the purpose of the migration class.
+     *
+     * @return string The description of the migration class
+     */
+    public function description()
+    {
+        return 'Sets Poll end_date to NULL by default (work around MySQL NO_ZERO_DATE)';
+    }
+
+    /**
+     * This method could check if the execute method should be called.
+     * It is called before the execute method.
+     *
+     * @param Connection|\PDO $connection The connection to database
+     * @return bool true if the Migration should be executed.
+     */
+    public function preCondition(Connection $connection)
+    {
+        $driver_name = $connection->getWrappedConnection()->getAttribute(\PDO::ATTR_DRIVER_NAME);
+
+        if ($driver_name === 'mysql') {
+            $stmt = $connection->prepare(
+                "SELECT Column_Default from Information_Schema.Columns where Table_Name = ? AND Column_Name = ?;"
+            );
+            $stmt->bindValue(1, Utils::table('poll'));
+            $stmt->bindValue(2, 'end_date');
+            $stmt->execute();
+            $default = $stmt->fetch(\PDO::FETCH_COLUMN);
+
+            return $default === null;
+        }
+        return true;
+    }
+
+    /**
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\DBALException
+     */
+    public function up(Schema $schema)
+    {
+        // We don't disable this migration even if legacy because it wasn't working correctly before
+        // $this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\Fix_MySQL_No_Zero_Date'), 'Migration has been executed in an earlier database migration system');
+        $this->skipIf($this->preCondition($this->connection), "Database server isn't MySQL or poll end_date default value was already NULL");
+        $poll = $schema->getTable(Utils::table('poll'));
+        $poll->changeColumn('end_date', ['default' => null, 'notnull' => false]);
+    }
+
+    public function down(Schema $schema)
+    {
+        // nothing
+    }
+}
diff --git a/app/classes/Framadate/Migration/AddColumn_collect_mail_In_poll.php b/app/classes/Framadate/Migrations/Version20180419170000.php
similarity index 52%
rename from app/classes/Framadate/Migration/AddColumn_collect_mail_In_poll.php
rename to app/classes/Framadate/Migrations/Version20180419170000.php
index 5ede344906e6d98f7073e2e95a925a0804e00657..8c9952f04a5af45178866d6491a4a1e3dd934677 100644
--- a/app/classes/Framadate/Migration/AddColumn_collect_mail_In_poll.php
+++ b/app/classes/Framadate/Migrations/Version20180419170000.php
@@ -16,55 +16,50 @@
  * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
  * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
  */
-namespace Framadate\Migration;
+namespace DoctrineMigrations;
 
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
 use Framadate\Utils;
 
 /**
- * This migration adds the field uniqId on the vote table.
+ * This migration adds the column collect_users_mail in the poll table
  *
  * @package Framadate\Migration
- * @version 0.9
+ * @version 1.2
  */
-class AddColumn_collect_mail_In_poll implements Migration {
-    function __construct() {
-    }
-
+class Version20180419170000 extends AbstractMigration
+{
     /**
      * This method should describe in english what is the purpose of the migration class.
      *
      * @return string The description of the migration class
      */
-    function description() {
+    public function description()
+    {
         return 'Add column collect_users_mail in table poll';
     }
 
     /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the Migration should be executed.
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\DBALException
      */
-    function preCondition(\PDO $pdo) {
-        return true;
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\AddColumn_collect_mail_In_poll'), 'Migration has been executed in an earlier database migration system');
+        $poll = $schema->getTable(Utils::table('poll'));
+        $poll->addColumn('collect_users_mail', 'boolean', ['default' => false]);
     }
 
     /**
-     * This method is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the execution succeeded
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
      */
-    function execute(\PDO $pdo) {
-        $this->alterVoteTable($pdo);
-
-        return true;
-    }
-
-    private function alterVoteTable(\PDO $pdo) {
-        $pdo->exec('
-        ALTER TABLE `' . Utils::table('poll') . '`
-        ADD `collect_users_mail` TINYINT DEFAULT 0;');
+    public function down(Schema $schema)
+    {
+        $poll = $schema->getTable(Utils::table('poll'));
+        $poll->dropColumn('collect_users_mail');
     }
 }
diff --git a/app/classes/Framadate/Migration/AddColumn_mail_In_vote.php b/app/classes/Framadate/Migrations/Version20180419180000.php
similarity index 52%
rename from app/classes/Framadate/Migration/AddColumn_mail_In_vote.php
rename to app/classes/Framadate/Migrations/Version20180419180000.php
index 65c9631f3f07be504e170a7cdbc4b7b29c8bac5b..701b92151d3698084c8cb865434b7ffdbeae6f98 100644
--- a/app/classes/Framadate/Migration/AddColumn_mail_In_vote.php
+++ b/app/classes/Framadate/Migrations/Version20180419180000.php
@@ -16,55 +16,50 @@
  * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
  * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
  */
-namespace Framadate\Migration;
+namespace DoctrineMigrations;
 
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
 use Framadate\Utils;
 
 /**
- * This migration adds the field uniqId on the vote table.
+ * This migration adds the column mail in the vote table
  *
  * @package Framadate\Migration
- * @version 0.9
+ * @version 1.2
  */
-class AddColumn_mail_In_vote implements Migration {
-    function __construct() {
-    }
-
+class Version20180419180000 extends AbstractMigration
+{
     /**
      * This method should describe in english what is the purpose of the migration class.
      *
      * @return string The description of the migration class
      */
-    function description() {
+    public function description()
+    {
         return 'Add column mail in table vote';
     }
 
     /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the Migration should be executed.
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
+     * @throws \Doctrine\DBAL\DBALException
      */
-    function preCondition(\PDO $pdo) {
-        return true;
+    public function up(Schema $schema)
+    {
+        $this->skipIf($this->legacyCheck($schema, 'Framadate\Migration\AddColumn_collect_mail_In_poll'), 'Migration has been executed in an earlier database migration system');
+        $vote = $schema->getTable(Utils::table('vote'));
+        $vote->addColumn('mail', 'string', ['default' => null, 'notnull' => false]);
     }
 
     /**
-     * This method is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true is the execution succeeded
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Schema\SchemaException
      */
-    function execute(\PDO $pdo) {
-        $this->alterVoteTable($pdo);
-
-        return true;
-    }
-
-    private function alterVoteTable(\PDO $pdo) {
-        $pdo->exec('
-        ALTER TABLE `' . Utils::table('vote') . '`
-        ADD `mail` VARCHAR(320) DEFAULT NULL;');
+    public function down(Schema $schema)
+    {
+        $vote = $schema->getTable(Utils::table('vote'));
+        $vote->dropColumn('mail');
     }
 }
diff --git a/app/classes/Framadate/Migration/Migration.php b/app/classes/Framadate/Migrations/Version20180419190000.php
similarity index 54%
rename from app/classes/Framadate/Migration/Migration.php
rename to app/classes/Framadate/Migrations/Version20180419190000.php
index c4bed57f70edf21886c45871758e4d8ea24e7dda..165a3cac94ea5bee6b0e6c2f4b31b39a9b22cb58 100644
--- a/app/classes/Framadate/Migration/Migration.php
+++ b/app/classes/Framadate/Migrations/Version20180419190000.php
@@ -16,31 +16,45 @@
  * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
  * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
  */
-namespace Framadate\Migration;
+namespace DoctrineMigrations;
 
-interface Migration {
+use Doctrine\DBAL\Schema\Schema;
+use Framadate\AbstractMigration;
+use Framadate\Utils;
+
+/**
+ * This migration adds the column mail in the vote table
+ *
+ * @package Framadate\Migration
+ * @version 1.2
+ */
+class Version20180419190000 extends AbstractMigration
+{
     /**
      * This method should describe in english what is the purpose of the migration class.
      *
      * @return string The description of the migration class
      */
-    function description();
+    public function description()
+    {
+        return 'Remove the old migration table';
+    }
 
     /**
-     * This method could check if the execute method should be called.
-     * It is called before the execute method.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true if the Migration should be executed
+     * @param Schema $schema
+     * @throws \Doctrine\DBAL\Migrations\SkipMigrationException
      */
-    function preCondition(\PDO $pdo);
+    public function up(Schema $schema)
+    {
+        $this->skipIf(!$schema->hasTable(Utils::table(MIGRATION_TABLE)), "The old migration table wasn't created, no need to delete it.");
+        $schema->dropTable(Utils::table(MIGRATION_TABLE));
+    }
 
     /**
-     * This methode is called only one time in the migration page.
-     *
-     * @param \PDO $pdo The connection to database
-     * @return bool true if the execution succeeded
+     * @param Schema $schema
      */
-    function execute(\PDO $pdo);
+    public function down(Schema $schema)
+    {
+        // No need to recreate legacy migration table
+    }
 }
- 
\ No newline at end of file
diff --git a/app/classes/Framadate/Repositories/AbstractRepository.php b/app/classes/Framadate/Repositories/AbstractRepository.php
index 28a8b2f6e664fbea9e1c80742fb42b4a89e17524..fa7b752bf1bd56b2992ef41f08680851daf2ce65 100644
--- a/app/classes/Framadate/Repositories/AbstractRepository.php
+++ b/app/classes/Framadate/Repositories/AbstractRepository.php
@@ -1,43 +1,69 @@
 <?php
 namespace Framadate\Repositories;
 
-use Framadate\FramaDB;
+use Doctrine\DBAL\Connection;
 
 abstract class AbstractRepository {
     /**
-     * @var FramaDB
+     * @var Connection
      */
-    private $connect;
+    protected $connect;
 
     /**
      * PollRepository constructor.
-     * @param FramaDB $connect
+     * @param Connection $connect
      */
-    function __construct(FramaDB $connect) {
+    public function __construct(Connection $connect) {
         $this->connect = $connect;
+        $this->connect->setFetchMode(\PDO::FETCH_OBJ);
     }
 
-    public function beginTransaction() {
+    public function beginTransaction()
+    {
         $this->connect->beginTransaction();
     }
 
-    public function commit() {
+    /**
+     * @throws \Doctrine\DBAL\ConnectionException
+     */
+    public function commit()
+    {
         $this->connect->commit();
     }
 
-    function rollback() {
+    /**
+     * @throws \Doctrine\DBAL\ConnectionException
+     */
+    public function rollback()
+    {
         $this->connect->rollback();
     }
 
-    public function prepare($sql) {
+    /**
+     * @param string $sql
+     * @throws \Doctrine\DBAL\DBALException
+     * @return bool|\Doctrine\DBAL\Driver\Statement|\PDOStatement
+     */
+    public function prepare($sql)
+    {
         return $this->connect->prepare($sql);
     }
 
-    function query($sql) {
+    /**
+     * @param string $sql
+     * @throws \Doctrine\DBAL\DBALException
+     * @return bool|\Doctrine\DBAL\Driver\Statement|\PDOStatement
+     */
+    public function query($sql)
+    {
         return $this->connect->query($sql);
     }
 
-    function lastInsertId() {
+    /**
+     * @return string
+     */
+    public function lastInsertId()
+    {
         return $this->connect->lastInsertId();
     }
 }
diff --git a/app/classes/Framadate/Repositories/CommentRepository.php b/app/classes/Framadate/Repositories/CommentRepository.php
index 262ed0aaf8520989517f326e7aae3493410a58c0..c122361cdbc89ba014588c3aa1bfc50df1878fa6 100644
--- a/app/classes/Framadate/Repositories/CommentRepository.php
+++ b/app/classes/Framadate/Repositories/CommentRepository.php
@@ -1,16 +1,16 @@
 <?php
 namespace Framadate\Repositories;
 
-use Framadate\FramaDB;
 use Framadate\Utils;
 
 class CommentRepository extends AbstractRepository {
-    function __construct(FramaDB $connect) {
-        parent::__construct($connect);
-    }
-
-    function findAllByPollId($poll_id) {
-        $prepared = $this->prepare('SELECT * FROM `' . Utils::table('comment') . '` WHERE poll_id = ? ORDER BY id');
+    /**
+     * @param $poll_id
+     * @throws \Doctrine\DBAL\DBALException
+     * @return array
+     */
+    public function findAllByPollId($poll_id) {
+        $prepared = $this->prepare('SELECT * FROM ' . Utils::table('comment') . ' WHERE poll_id = ? ORDER BY id');
         $prepared->execute([$poll_id]);
 
         return $prepared->fetchAll();
@@ -24,32 +24,44 @@ class CommentRepository extends AbstractRepository {
      * @param $comment
      * @return bool
      */
-    function insert($poll_id, $name, $comment) {
-        $prepared = $this->prepare('INSERT INTO `' . Utils::table('comment') . '` (poll_id, name, comment) VALUES (?,?,?)');
-
-        return $prepared->execute([$poll_id, $name, $comment]);
+    function insert($poll_id, $name, $comment)
+    {
+        return $this->connect->insert(Utils::table('comment'), ['poll_id' => $poll_id, 'name' => $name, 'comment' => $comment]) > 0;
     }
 
-    function deleteById($poll_id, $comment_id) {
-        $prepared = $this->prepare('DELETE FROM `' . Utils::table('comment') . '` WHERE poll_id = ? AND id = ?');
-
-        return $prepared->execute([$poll_id, $comment_id]);
+    /**
+     * @param $poll_id
+     * @param $comment_id
+     * @throws \Doctrine\DBAL\Exception\InvalidArgumentException
+     * @return bool
+     */
+    function deleteById($poll_id, $comment_id)
+    {
+        return $this->connect->delete(Utils::table('comment'), ['poll_id' => $poll_id, 'id' => $comment_id]) > 0;
     }
 
     /**
      * Delete all comments of a given poll.
      *
      * @param $poll_id int The ID of the given poll.
-     * @return bool|null true if action succeeded.
+     * @throws \Doctrine\DBAL\Exception\InvalidArgumentException
+     * @return bool true if action succeeded.
      */
-    function deleteByPollId($poll_id) {
-        $prepared = $this->prepare('DELETE FROM `' . Utils::table('comment') . '` WHERE poll_id = ?');
-
-        return $prepared->execute([$poll_id]);
+    function deleteByPollId($poll_id)
+    {
+        return $this->connect->delete(Utils::table('comment'), ['poll_id' => $poll_id]) > 0;
     }
 
-    public function exists($poll_id, $name, $comment) {
-        $prepared = $this->prepare('SELECT 1 FROM `' . Utils::table('comment') . '` WHERE poll_id = ? AND name = ? AND comment = ?');
+    /**
+     * @param $poll_id
+     * @param $name
+     * @param $comment
+     * @throws \Doctrine\DBAL\DBALException
+     * @return bool
+     */
+    public function exists($poll_id, $name, $comment)
+    {
+        $prepared = $this->prepare('SELECT 1 FROM ' . Utils::table('comment') . ' WHERE poll_id = ? AND name = ? AND comment = ?');
         $prepared->execute([$poll_id, $name, $comment]);
 
         return $prepared->rowCount() > 0;
diff --git a/app/classes/Framadate/Repositories/PollRepository.php b/app/classes/Framadate/Repositories/PollRepository.php
index 8c1e7f4e49cfdc60aa6f78be841836821e0dc0b9..4efda19ca975d75ecd64127ee7d859bc29c75aff 100644
--- a/app/classes/Framadate/Repositories/PollRepository.php
+++ b/app/classes/Framadate/Repositories/PollRepository.php
@@ -1,25 +1,45 @@
 <?php
 namespace Framadate\Repositories;
 
-use Framadate\FramaDB;
 use Framadate\Utils;
 use PDO;
 
 class PollRepository extends AbstractRepository {
-    function __construct(FramaDB $connect) {
-        parent::__construct($connect);
-    }
-
-    public function insertPoll($poll_id, $admin_poll_id, $form) {
-        $sql = 'INSERT INTO `' . Utils::table('poll') . '`
-          (id, admin_id, title, description, admin_name, admin_mail, end_date, format, editable, receiveNewVotes, receiveNewComments, hidden, password_hash, results_publicly_visible, ValueMax, collect_users_mail)
-          VALUES (?,?,?,?,?,?,FROM_UNIXTIME(?),?,?,?,?,?,?,?,?,?)';
-        $prepared = $this->prepare($sql);
-        $prepared->execute([$poll_id, $admin_poll_id, $form->title, $form->description, $form->admin_name, $form->admin_mail, $form->end_date, $form->format, ($form->editable>=0 && $form->editable<=2) ? $form->editable : 0, $form->receiveNewVotes ? 1 : 0, $form->receiveNewComments ? 1 : 0, $form->hidden ? 1 : 0, $form->password_hash, $form->results_publicly_visible ? 1 : 0, $form->ValueMax, $form->collect_users_mail? 1 : 0]);
+    /**
+     * @param $poll_id
+     * @param $admin_poll_id
+     * @param $form
+     */
+    public function insertPoll($poll_id, $admin_poll_id, $form)
+    {
+        $this->connect->insert(Utils::table('poll'), [
+            'id' => $poll_id,
+            'admin_id' => $admin_poll_id,
+            'title' => $form->title,
+            'description' => $form->description,
+            'admin_name' => $form->admin_name,
+            'admin_mail' => $form->admin_mail,
+            'end_date' => (new \DateTime)->setTimestamp($form->end_date)->format('Y-m-d H:i:s'),
+            'format' => $form->format,
+            'editable' => ($form->editable>=0 && $form->editable<=2) ? $form->editable : 0,
+            'receiveNewVotes' => $form->receiveNewVotes ? 1 : 0,
+            'receiveNewComments' => $form->receiveNewComments ? 1 : 0,
+            'hidden' => $form->hidden ? 1 : 0,
+            'password_hash' => $form->password_hash,
+            'results_publicly_visible' => $form->results_publicly_visible ? 1 : 0,
+            'ValueMax' => $form->ValueMax,
+            'collect_users_mail' => $form->collect_users_mail? 1 : 0,
+        ]);
     }
 
-    function findById($poll_id) {
-        $prepared = $this->prepare('SELECT * FROM `' . Utils::table('poll') . '` WHERE id = ?');
+    /**
+     * @param $poll_id
+     * @throws \Doctrine\DBAL\DBALException
+     * @return mixed
+     */
+    public function findById($poll_id)
+    {
+        $prepared = $this->prepare('SELECT * FROM ' . Utils::table('poll') . ' WHERE id = ?');
 
         $prepared->execute([$poll_id]);
         $poll = $prepared->fetch();
@@ -28,8 +48,13 @@ class PollRepository extends AbstractRepository {
         return $poll;
     }
 
+    /**
+     * @param $admin_poll_id
+     * @throws \Doctrine\DBAL\DBALException
+     * @return mixed
+     */
     public function findByAdminId($admin_poll_id) {
-        $prepared = $this->prepare('SELECT * FROM `' . Utils::table('poll') . '` WHERE admin_id = ?');
+        $prepared = $this->prepare('SELECT * FROM ' . Utils::table('poll') . ' WHERE admin_id = ?');
 
         $prepared->execute([$admin_poll_id]);
         $poll = $prepared->fetch();
@@ -38,42 +63,75 @@ class PollRepository extends AbstractRepository {
         return $poll;
     }
 
+    /**
+     * @param $poll_id
+     * @throws \Doctrine\DBAL\DBALException
+     * @return bool
+     */
     public function existsById($poll_id) {
-        $prepared = $this->prepare('SELECT 1 FROM `' . Utils::table('poll') . '` WHERE id = ?');
+        $prepared = $this->prepare('SELECT 1 FROM ' . Utils::table('poll') . ' WHERE id = ?');
 
         $prepared->execute([$poll_id]);
 
         return $prepared->rowCount() > 0;
     }
 
+    /**
+     * @param $admin_poll_id
+     * @throws \Doctrine\DBAL\DBALException
+     * @return bool
+     */
     public function existsByAdminId($admin_poll_id) {
-        $prepared = $this->prepare('SELECT 1 FROM `' . Utils::table('poll') . '` WHERE admin_id = ?');
+        $prepared = $this->prepare('SELECT 1 FROM ' . Utils::table('poll') . ' WHERE admin_id = ?');
 
         $prepared->execute([$admin_poll_id]);
 
         return $prepared->rowCount() > 0;
     }
 
-    function update($poll) {
-        $prepared = $this->prepare('UPDATE `' . Utils::table('poll') . '` SET title=?, admin_name=?, admin_mail=?, description=?, end_date=?, active=?, editable=?, hidden=?, password_hash=?, results_publicly_visible=? WHERE id = ?');
-
-        return $prepared->execute([$poll->title, $poll->admin_name, $poll->admin_mail, $poll->description, $poll->end_date, $poll->active, ($poll->editable>=0 && $poll->editable<=2) ? $poll->editable  : 0, $poll->hidden ? 1 : 0, $poll->password_hash, $poll->results_publicly_visible ? 1 : 0, $poll->id]);
+    /**
+     * @param $poll
+     * @return bool
+     */
+    public function update($poll)
+    {
+        return $this->connect->update(Utils::table('poll'), [
+            'title' => $poll->title,
+            'admin_name' => $poll->admin_name,
+            'admin_mail' => $poll->admin_mail,
+            'description' => $poll->description,
+            'end_date' => $poll->end_date, # TODO : Harmonize dates between here and insert
+            'active' => $poll->active,
+            'editable' => $poll->editable >= 0 && $poll->editable <= 2 ? $poll->editable : 0,
+            'hidden' => $poll->hidden ? 1 : 0,
+            'password_hash' => $poll->password_hash,
+            'results_publicly_visible' => $poll->results_publicly_visible ? 1 : 0
+        ], [
+            'id' => $poll->id
+        ]) > 0;
     }
 
-    function deleteById($poll_id) {
-        $prepared = $this->prepare('DELETE FROM `' . Utils::table('poll') . '` WHERE id = ?');
-
-        return $prepared->execute([$poll_id]);
+    /**
+     * @param $poll_id
+     * @throws \Doctrine\DBAL\Exception\InvalidArgumentException
+     * @return bool
+     */
+    public function deleteById($poll_id)
+    {
+        return $this->connect->delete(Utils::table('poll'), ['id' => $poll_id]) > 0;
     }
 
     /**
      * Find old polls. Limit: 20.
      *
+     * @param int $limit
+     * @throws \Doctrine\DBAL\DBALException
      * @return array Array of old polls
      */
-    public function findOldPolls() {
-        $prepared = $this->prepare('SELECT * FROM `' . Utils::table('poll') . '` WHERE DATE_ADD(`end_date`, INTERVAL ' . PURGE_DELAY . ' DAY) < NOW() AND `end_date` != 0 LIMIT 20');
-        $prepared->execute([]);
+    public function findOldPolls($limit = 20)
+    {
+        $prepared = $this->prepare('SELECT * FROM ' . Utils::table('poll') . ' WHERE DATE_ADD(end_date, INTERVAL ? DAY) < NOW() AND end_date != 0 LIMIT ?');
+        $prepared->execute([PURGE_DELAY, $limit]);
 
         return $prepared->fetchAll();
     }
@@ -84,52 +142,53 @@ class PollRepository extends AbstractRepository {
      * @param array $search Array of search : ['id'=>..., 'title'=>..., 'name'=>..., 'mail'=>...]
      * @param int $start The number of first entry to select
      * @param int $limit The number of entries to find
+     * @throws \Doctrine\DBAL\DBALException
      * @return array The found polls
      */
     public function findAll($search, $start, $limit) {
         // Polls
-        
+
         $request  = "";
         $request .= "SELECT p.*,";
-        $request .= "    (SELECT count(1) FROM `" . Utils::table('vote') . "` v WHERE p.id=v.poll_id) votes";
-        $request .= " FROM `" . Utils::table('poll') . "` p";
+        $request .= "    (SELECT count(1) FROM " . Utils::table('vote') . " v WHERE p.id=v.poll_id) votes";
+        $request .= " FROM " . Utils::table('poll') . " p";
         $request .= " WHERE 1";
-        
+
         $values = [];
-        
+
         if (!empty($search["poll"])) {
             $request .= " AND p.id LIKE :poll";
             $values["poll"] = "{$search["poll"]}%";
         }
-        
+
         $fields = [
             // key of $search => column name
             "title" => "title",
             "name" => "admin_name",
             "mail" => "admin_mail",
         ];
-        
+
         foreach ($fields as $searchKey => $columnName) {
             if (empty($search[$searchKey])) {
                 continue;
             }
-            
+
             $request .= " AND p.$columnName LIKE :$searchKey";
             $values[$searchKey] = "%{$search[$searchKey]}%";
         }
-        
+
         $request .= "  ORDER BY p.title ASC";
         $request .= "  LIMIT :start, :limit";
-        
+
         $prepared = $this->prepare($request);
-        
+
         foreach ($values as $searchKey => $value) {
             $prepared->bindParam(":$searchKey", $value, PDO::PARAM_STR);
         }
-        
+
         $prepared->bindParam(':start', $start, PDO::PARAM_INT);
         $prepared->bindParam(':limit', $limit, PDO::PARAM_INT);
-        
+
         $prepared->execute();
 
         return $prepared->fetchAll();
@@ -139,26 +198,28 @@ class PollRepository extends AbstractRepository {
      * Find all polls that are created with the given admin mail.
      *
      * @param string $mail Email address of the poll admin
+     * @throws \Doctrine\DBAL\DBALException
      * @return array The list of matching polls
      */
     public function findAllByAdminMail($mail) {
-        $prepared = $this->prepare('SELECT * FROM `' . Utils::table('poll') . '` WHERE admin_mail = :admin_mail');
+        $prepared = $this->prepare('SELECT * FROM ' . Utils::table('poll') . ' WHERE admin_mail = :admin_mail');
         $prepared->execute(['admin_mail' => $mail]);
 
         return $prepared->fetchAll();
     }
 
     /**
-     * Get the total number of polls in databse.
+     * Get the total number of polls in database.
      *
      * @param array $search Array of search : ['id'=>..., 'title'=>..., 'name'=>...]
+     * @throws \Doctrine\DBAL\DBALException
      * @return int The number of polls
      */
     public function count($search = null) {
         // Total count
         $prepared = $this->prepare('
 SELECT count(1) nb
-  FROM `' . Utils::table('poll') . '` p
+  FROM ' . Utils::table('poll') . ' p
  WHERE (:id = "" OR p.id LIKE :id)
    AND (:title = "" OR p.title LIKE :title)
    AND (:name = "" OR p.admin_name LIKE :name)
diff --git a/app/classes/Framadate/Repositories/RepositoryFactory.php b/app/classes/Framadate/Repositories/RepositoryFactory.php
index 810d3912d9b9284cb06c66daa44e27eca9d4a2f8..76910eba75552c990ebdc11b159dee331e426134 100644
--- a/app/classes/Framadate/Repositories/RepositoryFactory.php
+++ b/app/classes/Framadate/Repositories/RepositoryFactory.php
@@ -18,7 +18,7 @@
  */
 namespace Framadate\Repositories;
 
-use Framadate\FramaDB;
+use Doctrine\DBAL\Connection;
 
 class RepositoryFactory {
     private static $connect;
@@ -29,9 +29,9 @@ class RepositoryFactory {
     private static $commentRepository;
 
     /**
-     * @param FramaDB $connect
+     * @param Connection $connect
      */
-    static function init(FramaDB $connect) {
+    static function init(Connection $connect) {
         self::$connect = $connect;
     }
 
diff --git a/app/classes/Framadate/Repositories/SlotRepository.php b/app/classes/Framadate/Repositories/SlotRepository.php
index 4c9c40f274d89026e96ad533121ca6c6b5e5977f..51390736083402d6e888a6defbc4c6264449108b 100644
--- a/app/classes/Framadate/Repositories/SlotRepository.php
+++ b/app/classes/Framadate/Repositories/SlotRepository.php
@@ -4,28 +4,23 @@
  * is not distributed with this file, you can obtain one at
  * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
  *
- * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Rapha�l DROZ
  * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
  *
  * =============================
  *
- * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * Ce logiciel est r�gi par la licence CeCILL-B. Si une copie de cette licence
  * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
  * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
  *
- * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Rapha�l DROZ
  * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
  */
 namespace Framadate\Repositories;
 
-use Framadate\FramaDB;
 use Framadate\Utils;
 
 class SlotRepository extends AbstractRepository {
-    function __construct(FramaDB $connect) {
-        parent::__construct($connect);
-    }
-
     /**
      * Insert a bulk of slots.
      *
@@ -33,11 +28,9 @@ class SlotRepository extends AbstractRepository {
      * @param array $choices
      */
     public function insertSlots($poll_id, $choices) {
-        $prepared = $this->prepare('INSERT INTO `' . Utils::table('slot') . '` (poll_id, title, moments) VALUES (?, ?, ?)');
-
         foreach ($choices as $choice) {
             // We prepared the slots (joined by comas)
-            $joinedSlots = '';
+            $joinedSlots = null;
             $first = true;
             foreach ($choice->getSlots() as $slot) {
                 if ($first) {
@@ -49,16 +42,18 @@ class SlotRepository extends AbstractRepository {
             }
 
             // We execute the insertion
-            if (empty($joinedSlots)) {
-                $prepared->execute([$poll_id, $choice->getName(), null]);
-            } else {
-                $prepared->execute([$poll_id, $choice->getName(), $joinedSlots]);
-            }
+            $this->connect->insert(Utils::table('slot'), ['poll_id' => $poll_id, 'title' => $choice->getName(), 'moments' => $joinedSlots]);
         }
     }
 
-    function listByPollId($poll_id) {
-        $prepared = $this->prepare('SELECT * FROM `' . Utils::table('slot') . '` WHERE poll_id = ? ORDER BY id');
+    /**
+     * @param $poll_id
+     * @throws \Doctrine\DBAL\DBALException
+     * @return array
+     */
+    public function listByPollId($poll_id)
+    {
+        $prepared = $this->prepare('SELECT * FROM ' . Utils::table('slot') . ' WHERE poll_id = ? ORDER BY id');
         $prepared->execute([$poll_id]);
 
         return $prepared->fetchAll();
@@ -69,10 +64,11 @@ class SlotRepository extends AbstractRepository {
      *
      * @param $poll_id int The ID of the poll
      * @param $datetime int The datetime of the slot
+     * @throws \Doctrine\DBAL\DBALException
      * @return mixed Object The slot found, or null
      */
     function findByPollIdAndDatetime($poll_id, $datetime) {
-        $prepared = $this->prepare('SELECT * FROM `' . Utils::table('slot') . '` WHERE poll_id = ? AND SUBSTRING_INDEX(title, \'@\', 1) = ?');
+        $prepared = $this->prepare('SELECT * FROM ' . Utils::table('slot') . ' WHERE poll_id = ? AND SUBSTRING_INDEX(title, \'@\', 1) = ?');
 
         $prepared->execute([$poll_id, $datetime]);
         $slot = $prepared->fetch();
@@ -89,10 +85,9 @@ class SlotRepository extends AbstractRepository {
      * @param $moments mixed|null The moments joined with ","
      * @return bool true if action succeeded
      */
-    function insert($poll_id, $title, $moments) {
-        $prepared = $this->prepare('INSERT INTO `' . Utils::table('slot') . '` (poll_id, title, moments) VALUES (?,?,?)');
-
-        return $prepared->execute([$poll_id, $title, $moments]);
+    function insert($poll_id, $title, $moments)
+    {
+        return $this->connect->insert(Utils::table('slot'), ['poll_id' => $poll_id, 'title' => $title, 'moments' => $moments]) > 0;
     }
 
     /**
@@ -103,10 +98,9 @@ class SlotRepository extends AbstractRepository {
      * @param $newMoments mixed The new moments
      * @return bool|null true if action succeeded.
      */
-    function update($poll_id, $datetime, $newMoments) {
-        $prepared = $this->prepare('UPDATE `' . Utils::table('slot') . '` SET moments = ? WHERE poll_id = ? AND title = ?');
-
-        return $prepared->execute([$newMoments, $poll_id, $datetime]);
+    function update($poll_id, $datetime, $newMoments)
+    {
+        return $this->connect->update(Utils::table('slot'), ['moments' => $newMoments], ['poll_id' => $poll_id, 'title' => $datetime]) > 0;
     }
 
     /**
@@ -114,15 +108,21 @@ class SlotRepository extends AbstractRepository {
      *
      * @param $poll_id int The ID of the poll
      * @param $datetime mixed The datetime of the slot
+     * @throws \Doctrine\DBAL\DBALException
+     * @return bool
      */
-    function deleteByDateTime($poll_id, $datetime) {
-        $prepared = $this->prepare('DELETE FROM `' . Utils::table('slot') . '` WHERE poll_id = ? AND title = ?');
-        $prepared->execute([$poll_id, $datetime]);
+    public function deleteByDateTime($poll_id, $datetime)
+    {
+        return $this->connect->delete(Utils::table('slot'), ['poll_id' => $poll_id, 'title' => $datetime]) > 0;
     }
 
-    function deleteByPollId($poll_id) {
-        $prepared = $this->prepare('DELETE FROM `' . Utils::table('slot') . '` WHERE poll_id = ?');
-
-        return $prepared->execute([$poll_id]);
+    /**
+     * @param $poll_id
+     * @throws \Doctrine\DBAL\DBALException
+     * @return bool
+     */
+    public function deleteByPollId($poll_id)
+    {
+        return $this->connect->delete(Utils::table('slot'), ['poll_id' => $poll_id]) > 0;
     }
 }
diff --git a/app/classes/Framadate/Repositories/VoteRepository.php b/app/classes/Framadate/Repositories/VoteRepository.php
index 588a0ee32dbbc1b0d60c2f111067a80b5b9f5b12..d7a362b8db0103357341b15260a64f41f6f7f413 100644
--- a/app/classes/Framadate/Repositories/VoteRepository.php
+++ b/app/classes/Framadate/Repositories/VoteRepository.php
@@ -5,26 +5,35 @@ use Framadate\FramaDB;
 use Framadate\Utils;
 
 class VoteRepository extends AbstractRepository {
-    function __construct(FramaDB $connect) {
-        parent::__construct($connect);
-    }
-
-    function allUserVotesByPollId($poll_id) {
-        $prepared = $this->prepare('SELECT * FROM `' . Utils::table('vote') . '` WHERE poll_id = ? ORDER BY id');
+    /**
+     * @param $poll_id
+     * @throws \Doctrine\DBAL\DBALException
+     * @return array
+     */
+    public function allUserVotesByPollId($poll_id)
+    {
+        $prepared = $this->prepare('SELECT * FROM ' . Utils::table('vote') . ' WHERE poll_id = ? ORDER BY id');
         $prepared->execute([$poll_id]);
 
         return $prepared->fetchAll();
     }
 
-    function insertDefault($poll_id, $insert_position) {
-        $prepared = $this->prepare('UPDATE `' . Utils::table('vote') . '` SET choices = CONCAT(SUBSTRING(choices, 1, ?), " ", SUBSTRING(choices, ?)) WHERE poll_id = ?'); //#51 : default value for unselected vote
+    /**
+     * @param $poll_id
+     * @param $insert_position
+     * @throws \Doctrine\DBAL\DBALException
+     * @return bool
+     */
+    public function insertDefault($poll_id, $insert_position)
+    {
+        # TODO : Handle this on PHP's side
+        $prepared = $this->prepare('UPDATE ' . Utils::table('vote') . ' SET choices = CONCAT(SUBSTRING(choices, 1, ?), " ", SUBSTRING(choices, ?)) WHERE poll_id = ?'); //#51 : default value for unselected vote
 
         return $prepared->execute([$insert_position, $insert_position + 1, $poll_id]);
     }
 
     function insert($poll_id, $name, $choices, $token, $mail) {
-        $prepared = $this->prepare('INSERT INTO `' . Utils::table('vote') . '` (poll_id, name, choices, uniqId, mail) VALUES (?,?,?,?,?)');
-        $prepared->execute([$poll_id, $name, $choices, $token, $mail]);
+        $this->connect->insert(Utils::table('vote'), ['poll_id' => $poll_id, 'name' => $name, 'choices' => $choices, 'uniqId' => $token, 'mail' => $mail]);
 
         $newVote = new \stdClass();
         $newVote->poll_id = $poll_id;
@@ -32,33 +41,38 @@ class VoteRepository extends AbstractRepository {
         $newVote->name = $name;
         $newVote->choices = $choices;
         $newVote->uniqId = $token;
-	$newVote->mail=$mail;
+	    $newVote->mail=$mail;
 
         return $newVote;
     }
 
-    function deleteById($poll_id, $vote_id) {
-        $prepared = $this->prepare('DELETE FROM `' . Utils::table('vote') . '` WHERE poll_id = ? AND id = ?');
-
-        return $prepared->execute([$poll_id, $vote_id]);
+    /**
+     * @param $poll_id
+     * @param $vote_id
+     * @throws \Doctrine\DBAL\DBALException
+     * @return bool
+     */
+    public function deleteById($poll_id, $vote_id)
+    {
+        return $this->connect->delete(Utils::table('vote'), ['poll_id' => $poll_id, 'id' => $vote_id]) > 0;
     }
-    
+
     public function deleteOldVotesByPollId($poll_id, $votesToDelete) {
     	$prepared = $this->prepare('DELETE FROM `' . Utils::table('vote') . '` WHERE poll_id = ? ORDER BY `poll_id` ASC LIMIT ' . $votesToDelete);
 
         return $prepared->execute([$poll_id]);
     }
-    
+
     /**
      * Delete all votes of a given poll.
      *
      * @param $poll_id int The ID of the given poll.
+     * @throws \Doctrine\DBAL\DBALException
      * @return bool|null true if action succeeded.
      */
-    function deleteByPollId($poll_id) {
-        $prepared = $this->prepare('DELETE FROM `' . Utils::table('vote') . '` WHERE poll_id = ?');
-
-        return $prepared->execute([$poll_id]);
+    public function deleteByPollId($poll_id)
+    {
+        return $this->connect->delete(Utils::table('vote'), ['poll_id' => $poll_id]) > 0;
     }
 
     /**
@@ -66,18 +80,33 @@ class VoteRepository extends AbstractRepository {
      *
      * @param $poll_id int The ID of the poll
      * @param $index int The index of the vote into the poll
+     * @throws \Doctrine\DBAL\DBALException
      * @return bool|null true if action succeeded.
      */
-    function deleteByIndex($poll_id, $index) {
-        $prepared = $this->prepare('UPDATE `' . Utils::table('vote') . '` SET choices = CONCAT(SUBSTR(choices, 1, ?), SUBSTR(choices, ?)) WHERE poll_id = ?');
+    public function deleteByIndex($poll_id, $index)
+    {
+        $prepared = $this->prepare('UPDATE ' . Utils::table('vote') . ' SET choices = CONCAT(SUBSTR(choices, 1, ?), SUBSTR(choices, ?)) WHERE poll_id = ?');
 
         return $prepared->execute([$index, $index + 2, $poll_id]);
     }
 
-    function update($poll_id, $vote_id, $name, $choices, $mail) {
-        $prepared = $this->prepare('UPDATE `' . Utils::table('vote') . '` SET choices = ?, name = ?, mail = ? WHERE poll_id = ? AND id = ?');
-
-        return $prepared->execute([$choices, $name, $mail, $poll_id, $vote_id]);
+    /**
+     * @param $poll_id
+     * @param $vote_id
+     * @param $name
+     * @param $choices
+     * @return bool
+     */
+    public function update($poll_id, $vote_id, $name, $choices, $mail)
+    {
+        return $this->connect->update(Utils::table('vote'), [
+            'choices' => $choices,
+            'name' => $name,
+            'mail' => $mail,
+        ], [
+            'poll_id' => $poll_id,
+            'id' => $vote_id,
+        ]) > 0;
     }
 
     /**
@@ -85,24 +114,26 @@ class VoteRepository extends AbstractRepository {
      *
      * @param int $poll_id ID of the poll
      * @param string $name Name of the vote
+     * @throws \Doctrine\DBAL\DBALException
      * @return bool true if vote already exists
      */
     public function existsByPollIdAndName($poll_id, $name) {
-        $prepared = $this->prepare('SELECT 1 FROM `' . Utils::table('vote') . '` WHERE poll_id = ? AND name = ?');
+        $prepared = $this->prepare('SELECT 1 FROM ' . Utils::table('vote') . ' WHERE poll_id = ? AND name = ?');
         $prepared->execute([$poll_id, $name]);
         return $prepared->rowCount() > 0;
     }
-    
+
     /**
      * Check if name is already used for the given poll and another vote.
      *
      * @param int $poll_id ID of the poll
      * @param string $name Name of the vote
      * @param int $vote_id ID of the current vote
+     * @throws \Doctrine\DBAL\DBALException
      * @return bool true if vote already exists
      */
     public function existsByPollIdAndNameAndVoteId($poll_id, $name, $vote_id) {
-        $prepared = $this->prepare('SELECT 1 FROM `' . Utils::table('vote') . '` WHERE poll_id = ? AND name = ? AND id != ?');
+        $prepared = $this->prepare('SELECT 1 FROM ' . Utils::table('vote') . ' WHERE poll_id = ? AND name = ? AND id != ?');
         $prepared->execute([$poll_id, $name, $vote_id]);
         return $prepared->rowCount() > 0;
     }
diff --git a/app/classes/Framadate/Services/AdminPollService.php b/app/classes/Framadate/Services/AdminPollService.php
index 0f761505ea6c8dc77a20efbc1698666dd3ca6676..02e3c998fc8e4658849ecb16f22e3c4534f8de09 100644
--- a/app/classes/Framadate/Services/AdminPollService.php
+++ b/app/classes/Framadate/Services/AdminPollService.php
@@ -1,10 +1,9 @@
 <?php
 namespace Framadate\Services;
 
+use Doctrine\DBAL\Connection;
 use Framadate\Exception\MomentAlreadyExistsException;
-use Framadate\FramaDB;
 use Framadate\Repositories\RepositoryFactory;
-use Framadate\Utils;
 
 /**
  * Class AdminPollService
@@ -21,7 +20,7 @@ class AdminPollService {
     private $voteRepository;
     private $commentRepository;
 
-    function __construct(FramaDB $connect, PollService $pollService, LogService $logService) {
+    function __construct(Connection $connect, PollService $pollService, LogService $logService) {
         $this->connect = $connect;
         $this->pollService = $pollService;
         $this->logService = $logService;
@@ -35,7 +34,7 @@ class AdminPollService {
         global $config;
         if ($poll->end_date > $poll->creation_date) {
             return $this->pollRepository->update($poll);
-        }  
+        }
             return false;
     }
 
@@ -295,11 +294,10 @@ class AdminPollService {
             } elseif ($datetime < $rowDatetime) {
                 // We have to insert before this slot
                 break;
-            }  
+            }
                 $result->insert += count($moments);
         }
 
         return $result;
     }
 }
- 
\ No newline at end of file
diff --git a/app/classes/Framadate/Services/InstallService.php b/app/classes/Framadate/Services/InstallService.php
index 13672fa5636e435847d2c8746f87985781397062..ad7963de520c7818151f2ae5f5748348756f6a0a 100644
--- a/app/classes/Framadate/Services/InstallService.php
+++ b/app/classes/Framadate/Services/InstallService.php
@@ -17,6 +17,9 @@
  * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
  */
 namespace Framadate\Services;
+use Doctrine\DBAL\Configuration;
+use Doctrine\DBAL\DBALException;
+use Doctrine\DBAL\DriverManager;
 use Framadate\Utils;
 use Smarty;
 
@@ -33,7 +36,9 @@ class InstallService {
         'cleanUrl' => true,
 
         // Database configuration
-        'dbConnectionString' => 'mysql:host=<HOST>;dbname=<SCHEMA>;port=3306',
+        'dbName' => 'framadate',
+        'dbPort' => 3306,
+        'dbHost' => 'localhost',
         'dbUser' => 'root',
         'dbPassword' => '',
         'dbPrefix' => 'fd_',
@@ -50,12 +55,12 @@ class InstallService {
 
     public function install(Smarty &$smarty) {
         // Check values are present
-        if (empty($this->fields['appName']) || empty($this->fields['appMail']) || empty($this->fields['defaultLanguage']) || empty($this->fields['dbConnectionString']) || empty($this->fields['dbUser'])) {
+        if (empty($this->fields['appName']) || empty($this->fields['appMail']) || empty($this->fields['defaultLanguage']) || empty($this->fields['dbName']) || empty($this->fields['dbHost']) || empty($this->fields['dbPort']) || empty($this->fields['dbUser'])) {
             return $this->error('MISSING_VALUES');
         }
 
         // Connect to database
-        $connect = $this->connectTo($this->fields['dbConnectionString'], $this->fields['dbUser'], $this->fields['dbPassword']);
+        $connect = $this->connectTo($this->fields);
         if (!$connect) {
             return $this->error('CANT_CONNECT_TO_DATABASE');
         }
@@ -68,13 +73,25 @@ class InstallService {
         return $this->ok();
     }
 
-    function connectTo($connectionString, $user, $password) {
+    /**
+     * @param $fields
+     * @return \Doctrine\DBAL\Connection|null
+     */
+    function connectTo($fields) {
+        $doctrineConfig = new Configuration();
+        $connectionParams = [
+            'dbname' => $fields['dbName'],
+            'user' => $fields['dbUser'],
+            'password' => $fields['dbPassword'],
+            'host' => $fields['dbHost'],
+            'driver' => $fields['dbDriver'],
+            'charset' => $fields['dbDriver'] === 'pdo_mysql' ? 'utf8mb4' : 'utf8',
+        ];
         try {
-            $pdo = @new \PDO($connectionString, $user, $password);
-            $pdo->setAttribute(\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_OBJ);
-            $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
-            return $pdo;
-        } catch(\Exception $e) {
+            return DriverManager::getConnection($connectionParams, $doctrineConfig);
+        } catch (DBALException $e) {
+            $logger = new LogService();
+            $logger->log('ERROR', $e->getMessage());
             return null;
         }
     }
@@ -91,6 +108,7 @@ class InstallService {
 
     /**
      * @param $content
+     * @return bool|int
      */
     function writeToFile($content) {
         return @file_put_contents(CONF_FILENAME, $content);
diff --git a/app/classes/Framadate/Services/PollService.php b/app/classes/Framadate/Services/PollService.php
index f389cececafdaab0cbec8766b425fc80063f85a9..10d8e4978f8f4396aef42e0922a96101846d3cb3 100644
--- a/app/classes/Framadate/Services/PollService.php
+++ b/app/classes/Framadate/Services/PollService.php
@@ -18,11 +18,12 @@
  */
 namespace Framadate\Services;
 
+use Doctrine\DBAL\Connection;
+use Doctrine\DBAL\DBALException;
 use Framadate\Exception\AlreadyExistsException;
 use Framadate\Exception\ConcurrentEditionException;
 use Framadate\Exception\ConcurrentVoteException;
 use Framadate\Form;
-use Framadate\FramaDB;
 use Framadate\Repositories\RepositoryFactory;
 use Framadate\Security\Token;
 
@@ -35,7 +36,7 @@ class PollService {
     private $voteRepository;
     private $commentRepository;
 
-    function __construct(FramaDB $connect, LogService $logService) {
+    function __construct(Connection $connect, LogService $logService) {
         $this->connect = $connect;
         $this->logService = $logService;
         $this->pollRepository = RepositoryFactory::pollRepository();
@@ -48,6 +49,7 @@ class PollService {
      * Find a poll from its ID.
      *
      * @param $poll_id int The ID of the poll
+     * @throws \Doctrine\DBAL\DBALException
      * @return \stdClass|null The found poll, or null
      */
     function findById($poll_id) {
@@ -66,8 +68,18 @@ class PollService {
         return null;
     }
 
-    function allCommentsByPollId($poll_id) {
-        return $this->commentRepository->findAllByPollId($poll_id);
+    /**
+     * @param $poll_id
+     * @return array
+     */
+    public function allCommentsByPollId($poll_id)
+    {
+        try {
+            return $this->commentRepository->findAllByPollId($poll_id);
+        } catch (DBALException $e) {
+            $this->logService->log('error', $e->getMessage());
+            return null;
+        }
     }
 
     function allVotesByPollId($poll_id) {
diff --git a/app/classes/Framadate/Services/PurgeService.php b/app/classes/Framadate/Services/PurgeService.php
index 50c15df9cc4050105a38aff4b96a79aab73c92f8..92aecbe31e0020e04425547b612e1401789bbdb6 100644
--- a/app/classes/Framadate/Services/PurgeService.php
+++ b/app/classes/Framadate/Services/PurgeService.php
@@ -1,6 +1,7 @@
 <?php
 namespace Framadate\Services;
-use Framadate\FramaDB;
+use Doctrine\DBAL\Connection;
+use Doctrine\DBAL\DBALException;
 use Framadate\Repositories\RepositoryFactory;
 
 /**
@@ -15,7 +16,7 @@ class PurgeService {
     private $voteRepository;
     private $commentRepository;
 
-    function __construct(FramaDB $connect, LogService $logService) {
+    function __construct(Connection $connect, LogService $logService) {
         $this->logService = $logService;
         $this->pollRepository = RepositoryFactory::pollRepository();
         $this->slotRepository = RepositoryFactory::slotRepository();
@@ -36,23 +37,34 @@ class PurgeService {
      *
      * @return bool true is action succeeded
      */
-    function purgeOldPolls() {
-        $oldPolls = $this->pollRepository->findOldPolls();
-        $count = count($oldPolls);
+    public function purgeOldPolls() {
+        try {
+            $oldPolls = $this->pollRepository->findOldPolls();
+            $count = count($oldPolls);
 
-        if ($count > 0) {
-            $this->logService->log('EXPIRATION', 'Going to purge ' . $count . ' poll(s)...');
+            if ($count > 0) {
+                $this->logService->log('EXPIRATION', 'Going to purge ' . $count . ' poll(s)...');
 
-            foreach ($oldPolls as $poll) {
-                if ($this->purgePollById($poll->id)) {
-                    $this->logService->log('EXPIRATION_SUCCESS', 'id: ' . $poll->id . ', title:' . $poll->title . ', format: ' . $poll->format . ', admin: ' . $poll->admin_name);
-                } else {
-                    $this->logService->log('EXPIRATION_FAILED', 'id: ' . $poll->id . ', title:' . $poll->title . ', format: ' . $poll->format . ', admin: ' . $poll->admin_name);
+                foreach ($oldPolls as $poll) {
+                    if ($this->purgePollById($poll->id)) {
+                        $this->logService->log(
+                            'EXPIRATION_SUCCESS',
+                            'id: ' . $poll->id . ', title:' . $poll->title . ', format: ' . $poll->format . ', admin: ' . $poll->admin_name
+                        );
+                    } else {
+                        $this->logService->log(
+                            'EXPIRATION_FAILED',
+                            'id: ' . $poll->id . ', title:' . $poll->title . ', format: ' . $poll->format . ', admin: ' . $poll->admin_name
+                        );
+                    }
                 }
             }
-        }
 
-        return $count;
+            return $count;
+        } catch (DBALException $e) {
+            $this->logService->log('ERROR', $e->getMessage());
+            return false;
+        }
     }
     
     public function cleanDemoPoll() {
@@ -78,22 +90,25 @@ class PurgeService {
      * @param $poll_id int The ID of the poll
      * @return bool true is action succeeded
      */
-    function purgePollById($poll_id) {
+    private function purgePollById($poll_id) {
         $done = true;
 
-        $this->pollRepository->beginTransaction();
-        $done &= $this->commentRepository->deleteByPollId($poll_id);
-        $done &= $this->voteRepository->deleteByPollId($poll_id);
-        $done &= $this->slotRepository->deleteByPollId($poll_id);
-        $done &= $this->pollRepository->deleteById($poll_id);
+        try {
+            $this->pollRepository->beginTransaction();
+            $done &= $this->commentRepository->deleteByPollId($poll_id);
+            $done &= $this->voteRepository->deleteByPollId($poll_id);
+            $done &= $this->slotRepository->deleteByPollId($poll_id);
+            $done &= $this->pollRepository->deleteById($poll_id);
 
-        if ($done) {
-            $this->pollRepository->commit();
-        } else {
-            $this->pollRepository->rollback();
+            if ($done) {
+                $this->pollRepository->commit();
+            } else {
+                $this->pollRepository->rollback();
+            }
+        } catch (DBALException $e) {
+            $this->logService->log('ERROR', $e->getMessage());
         }
 
         return $done;
     }
 }
- 
\ No newline at end of file
diff --git a/app/classes/Framadate/Utils.php b/app/classes/Framadate/Utils.php
index 1f82f68bdabfd4e489914cdda3aee91bd63b7cb6..f106b6b7197a5956d08030466f21ded909115311 100644
--- a/app/classes/Framadate/Utils.php
+++ b/app/classes/Framadate/Utils.php
@@ -25,13 +25,16 @@ class Utils {
      * @return string Server name
      */
     public static function get_server_name() {
+        $serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
+        $serverPort = isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : '';
+
         $scheme = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')) ? 'https' : 'http';
-        $port = in_array($_SERVER['SERVER_PORT'], ['80', '443'], true) ? '' : ':' . $_SERVER['SERVER_PORT'];
+        $port = in_array($serverPort, ['80', '443'], true) ? '' : ':' . $serverPort;
         $dirname = dirname($_SERVER['SCRIPT_NAME']);
         $dirname = $dirname === '\\' ? '/' : $dirname . '/';
         $dirname = str_replace('/admin', '', $dirname);
         $dirname = str_replace('/action', '', $dirname);
-        $server_name = (defined('APP_URL') ? APP_URL : $_SERVER['SERVER_NAME']) . $port . $dirname;
+        $server_name = (defined('APP_URL') ? APP_URL : $serverName) . $port . $dirname;
 
         return $scheme . '://' . preg_replace('#//+#', '/', $server_name);
     }
diff --git a/app/inc/config.test.php b/app/inc/config.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..c642b2ddb04434e7533f22ba43cb948aac27882a
--- /dev/null
+++ b/app/inc/config.test.php
@@ -0,0 +1,116 @@
+<?php
+/**
+ * This software is governed by the CeCILL-B license. If a copy of this license
+ * is not distributed with this file, you can obtain one at
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.txt
+ *
+ * Authors of STUdS (initial project): Guilhem BORGHESI (borghesi@unistra.fr) and Raphaël DROZ
+ * Authors of Framadate/OpenSondage: Framasoft (https://github.com/framasoft)
+ *
+ * =============================
+ *
+ * Ce logiciel est régi par la licence CeCILL-B. Si une copie de cette licence
+ * ne se trouve pas avec ce fichier vous pouvez l'obtenir sur
+ * http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.txt
+ *
+ * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
+ * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
+ */
+
+// Fully qualified domain name of your webserver.
+// If this is unset or empty, the servername is determined automatically.
+// You *have to set this* if you are running Framadate behind a reverse proxy.
+// const APP_URL = '<www.mydomain.fr>';
+
+// Application name
+const NOMAPPLICATION = 'Framadate';
+
+// Database administrator email
+const ADRESSEMAILADMIN = 'admin@app.tld';
+
+// Email for automatic responses (you should set it to "no-reply")
+const ADRESSEMAILREPONSEAUTO = 'no@reply';
+
+// Database driver
+const DB_DRIVER = 'pdo_sqlite';
+
+// Database name
+const DB_NAME = 'framadate';
+
+// Database host
+const DB_HOST = '';
+
+// Database port
+const DB_PORT = '';
+
+// Database user
+const DB_USER = '';
+
+// Database password
+const DB_PASSWORD = '';
+
+// Table name prefix
+const TABLENAME_PREFIX = 'fd_';
+
+// Name of the table that stores migration script already executed
+const MIGRATION_TABLE = 'framadate_migration';
+
+// Default Language
+const DEFAULT_LANGUAGE = 'fr';
+
+// List of supported languages, fake constant as arrays can be used as constants only in PHP >=5.6
+$ALLOWED_LANGUAGES = [
+    'fr' => 'Français',
+    'en' => 'English',
+    'oc' => 'Occitan',
+    'es' => 'Español',
+    'de' => 'Deutsch',
+    'nl' => 'Dutch',
+    'it' => 'Italiano',
+    'br' => 'Brezhoneg',
+];
+
+// Path to image file with the title
+const IMAGE_TITRE = 'images/logo-framadate.png';
+
+// Clean URLs, boolean
+const URL_PROPRE = false;
+
+// Use REMOTE_USER data provided by web server
+const USE_REMOTE_USER =  true;
+
+// Path to the log file
+const LOG_FILE = 'admin/stdout.log';
+
+// Days (after expiration date) before purging a poll
+const PURGE_DELAY = 60;
+
+// Max slots per poll
+const MAX_SLOTS_PER_POLL = 366;
+
+// Number of seconds before we allow to resend an "Remember Edit Link" email.
+const TIME_EDIT_LINK_EMAIL = 60;
+
+// Config
+$config = [
+    /* general config */
+    'use_smtp' => false,                     // use email for polls creation/modification/responses notification
+    'smtp_options' => [
+        'host' => 'localhost',              // SMTP server (you could add many servers (main and backup for example) : use ";" like separator
+        'auth' => false,                    // Enable SMTP authentication
+        'username' => '',                   // SMTP username
+        'password' => '',                   // SMTP password
+        'secure' => '',                     // Enable encryption (false, tls or ssl)
+        'port' => 25,                       // TCP port to connect to
+    ],
+    /* home */
+    'show_what_is_that' => true,            // display "how to use" section
+    'show_the_software' => true,            // display technical information about the software
+    'show_cultivate_your_garden' => true,   // display "development and administration" information
+    /* create_classic_poll.php / create_date_poll.php */
+    'default_poll_duration' => 180,         // default values for the new poll duration (number of days).
+    /* create_classic_poll.php */
+    'user_can_add_img_or_link' => true,     // user can add link or URL when creating his poll.
+    'markdown_editor_by_default' => true,   // The markdown editor for the description is enabled by default
+    'provide_fork_awesome' => true,         // Whether the build-in fork-awesome should be provided
+];
diff --git a/app/inc/init.php b/app/inc/init.php
index 9950cfb88991fc0095067db5356eb3efc14703e5..ed973bec88b15fb6a868f61b87ca0e4869731136 100644
--- a/app/inc/init.php
+++ b/app/inc/init.php
@@ -16,8 +16,12 @@
  * Auteurs de STUdS (projet initial) : Guilhem BORGHESI (borghesi@unistra.fr) et Raphaël DROZ
  * Auteurs de Framadate/OpenSondage : Framasoft (https://github.com/framasoft)
  */
-use Framadate\FramaDB;
+
+use Doctrine\DBAL\Configuration;
+use Doctrine\DBAL\DBALException;
+use Doctrine\DBAL\DriverManager;
 use Framadate\Repositories\RepositoryFactory;
+use Framadate\Services\LogService;
 
 // Autoloading of dependencies with Composer
 require_once __DIR__ . '/../../vendor/autoload.php';
@@ -32,17 +36,41 @@ if (ini_get('date.timezone') === '') {
 }
 
 define('ROOT_DIR', __DIR__ . '/../../');
-define('CONF_FILENAME', ROOT_DIR . '/app/inc/config.php');
+
+$path = '/app/inc/config.php';
+if (getenv('APP_ENV') === 'test') {
+    $path = '/app/inc/config.test.php';
+}
+define('CONF_FILENAME', ROOT_DIR . $path);
 
 require_once __DIR__ . '/constants.php';
 
 if (is_file(CONF_FILENAME)) {
-    @include_once __DIR__ . '/config.php';
+    @include_once CONF_FILENAME;
 
     // Connection to database
-    $connect = new FramaDB(DB_CONNECTION_STRING, DB_USER, DB_PASSWORD);
-    RepositoryFactory::init($connect);
-    $err = 0;
+    $doctrineConfig = new Configuration();
+    $connectionParams = [
+        'dbname' => DB_NAME,
+        'user' => DB_USER,
+        'password' => DB_PASSWORD,
+        'host' => DB_HOST,
+        'driver' => DB_DRIVER,
+        'charset' => DB_DRIVER === 'pdo_mysql' ? 'utf8mb4' : 'utf8',
+    ];
+
+    if (DB_DRIVER === 'pdo_sqlite') {
+        $connectionParams['path'] = 'test_database.sqlite';
+    }
+
+    try {
+        $connect = DriverManager::getConnection($connectionParams, $doctrineConfig);
+        RepositoryFactory::init($connect);
+        $err = 0;
+    } catch (DBALException $e) {
+        $logger = new LogService();
+        $logger->log('ERROR', $e->getMessage());
+    }
 } else {
     define('NOMAPPLICATION', 'Framadate');
     define('DEFAULT_LANGUAGE', 'fr');
diff --git a/app/inc/smarty.php b/app/inc/smarty.php
index 487a72e2172e0cc812f113785a8abd11f8f1833e..f67e7e76bb0bc28129f526689b8c64a1abde8386 100644
--- a/app/inc/smarty.php
+++ b/app/inc/smarty.php
@@ -25,11 +25,14 @@ $smarty->setCompileDir(ROOT_DIR . COMPILE_DIR);
 $smarty->setCacheDir(ROOT_DIR . '/cache/');
 $smarty->caching = false;
 
+$serverName = isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : '';
+
 $smarty->assign('APPLICATION_NAME', NOMAPPLICATION);
 $smarty->assign('SERVER_URL', Utils::get_server_name());
 $smarty->assign('SCRIPT_NAME', $_SERVER['SCRIPT_NAME']);
 $smarty->assign('TITLE_IMAGE', IMAGE_TITRE);
-$smarty->assign('use_nav_js', strstr($_SERVER['SERVER_NAME'], 'framadate.org'));
+
+$smarty->assign('use_nav_js', strstr($serverName, 'framadate.org'));
 $smarty->assign('provide_fork_awesome', !isset($config['provide_fork_awesome']) || $config['provide_fork_awesome']);
 $smarty->assign('locale', $locale);
 $smarty->assign('langs', $ALLOWED_LANGUAGES);
diff --git a/app/tests/Framadate/Services/InputServiceUnitTest.php b/app/tests/Framadate/Services/InputServiceUnitTest.php
index 88579511787cdf599f56d94ae042d8a53bbae6ff..e326df43ac5e205c36effd59f8d32f54c197e877 100644
--- a/app/tests/Framadate/Services/InputServiceUnitTest.php
+++ b/app/tests/Framadate/Services/InputServiceUnitTest.php
@@ -1,32 +1,35 @@
 <?php
+
 namespace Framadate\Services;
 
 use Framadate\FramaTestCase;
 
 class InputServiceUnitTest extends FramaTestCase
 {
-    public function liste_emails() {
+    public function liste_emails()
+    {
         return [
             // valids addresses
-            "valid address" 		=> ["example@example.com", "example@example.com"],
-            "local address"			=> ["test@localhost", "test@localhost"],
-            "IP address"			=> ["ip.email@127.0.0.1", "ip.email@127.0.0.1"],
-            "with spaces arround" 	=> ["  with@spaces  ", "with@spaces"],
-            "unicode caracters" 	=> ["unicode.éà@idn-œ.com", "unicode.éà@idn-œ.com"],
+            "valid address" => ["example@example.com", "example@example.com"],
+            "local address" => ["test@localhost", "test@localhost"],
+            "IP address" => ["ip.email@127.0.0.1", "ip.email@127.0.0.1"],
+            "with spaces arround" => ["  with@spaces  ", "with@spaces"],
+            "unicode caracters" => ["unicode.éà@idn-œ.com", "unicode.éà@idn-œ.com"],
             // invalids addresses
-            "without domain" 		=> ["without-domain", FALSE],
-            "space inside" 			=> ["example example@example.com", FALSE],
-            "forbidden chars" 		=> ["special_chars.@example.com", FALSE],
+            "without domain" => ["without-domain", FALSE],
+            "space inside" => ["example example@example.com", FALSE],
+            "forbidden chars" => ["special_chars.@example.com", FALSE],
         ];
     }
 
-	/**
-	 * @dataProvider liste_emails
-	 */
-	public function test_filterMail($email, $expected) {
-		$inputService = new InputService();
-		$filtered = $inputService->filterMail($email);
+    /**
+     * @dataProvider liste_emails
+     */
+    public function test_filterMail($email, $expected)
+    {
+        $inputService = new InputService();
+        $filtered = $inputService->filterMail($email);
 
-		$this->assertSame($expected, $filtered);
-	}
+        $this->assertSame($expected, $filtered);
+    }
 }
diff --git a/bin/doctrine b/bin/doctrine
new file mode 100755
index 0000000000000000000000000000000000000000..5bcd655011aff50c07498c0c33a7813d410e0e4a
--- /dev/null
+++ b/bin/doctrine
@@ -0,0 +1,58 @@
+#!/usr/bin/env php
+<?php
+
+use Doctrine\DBAL\Migrations\Configuration\Configuration;
+use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper;
+use Framadate\Utils;
+use Symfony\Component\Console\Application;
+use Symfony\Component\Console\Helper\HelperSet;
+use Symfony\Component\Console\Helper\QuestionHelper;
+use Symfony\Component\Console\Input\ArgvInput;
+use Symfony\Component\Console\Output\ConsoleOutput;
+use Symfony\Component\Console\Style\SymfonyStyle;
+
+try {
+    require_once __DIR__ . '/../app/inc/init.php';
+
+    $input = new ArgvInput();
+    $output = new ConsoleOutput();
+    $style = new SymfonyStyle($input, $output);
+
+    if ($connect === null) {
+        throw new \Exception("Undefined database connection\n");
+    }
+
+    // replace the ConsoleRunner::run() statement with:
+    $cli = new Application('Doctrine Command Line Interface', VERSION);
+    $cli->setCatchExceptions(true);
+
+    $helperSet = new HelperSet(
+        [
+            'db' => new ConnectionHelper($connect),
+            'question' => new QuestionHelper(),
+        ]
+    );
+
+    $cli->setHelperSet($helperSet);
+
+    $migrateCommand = new \Doctrine\DBAL\Migrations\Tools\Console\Command\MigrateCommand();
+    $statusCommand = new \Doctrine\DBAL\Migrations\Tools\Console\Command\StatusCommand();
+
+    $migrationsDirectory = __DIR__ . '/../app/classes/Framadate/Migrations';
+
+    $configuration = new Configuration($connect);
+    $configuration->setMigrationsTableName(Utils::table(MIGRATION_TABLE) . '_new');
+    $configuration->setMigrationsDirectory($migrationsDirectory);
+    $configuration->setMigrationsNamespace('DoctrineMigrations');
+    $configuration->registerMigrationsFromDirectory($migrationsDirectory);
+    $migrateCommand->setMigrationConfiguration($configuration);
+    $statusCommand->setMigrationConfiguration($configuration);
+
+    // Register All Doctrine Commands
+    $cli->addCommands([$migrateCommand, $statusCommand]);
+
+    // Runs console application
+    $cli->run($input, $output);
+} catch (\Exception $e) {
+    $style->error($e->getMessage());
+}
diff --git a/composer.json b/composer.json
index d19901f92aed2dde62a749df1be9003a2bab0707..dffa432ef0c4c468b9eedca105f34164ccadbf45 100644
--- a/composer.json
+++ b/composer.json
@@ -62,7 +62,10 @@
         "ircmaxell/password-compat": "dev-master",
         "roave/security-advisories": "dev-master",
         "erusev/parsedown": "^1.7",
-        "egulias/email-validator": "~2.1"
+        "egulias/email-validator": "~2.1",
+        "doctrine/dbal": "^2.5",
+        "doctrine/migrations": "^1.5",
+        "sensiolabs/ansi-to-html": "^1.1"
     },
 
     "require-dev": {
diff --git a/composer.lock b/composer.lock
index e855b8c353a1eaa3f25a857774480e3e4528c774..011f65dd7997f7f1fe644a74bc175e5f9a2ddf60 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,34 +4,39 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "content-hash": "40759eac537218b0212ed923261b9850",
+    "content-hash": "94b1913890ddc3d8cf45cb64d0e77170",
     "packages": [
         {
-            "name": "doctrine/lexer",
-            "version": "v1.0.1",
+            "name": "doctrine/annotations",
+            "version": "v1.4.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/doctrine/lexer.git",
-                "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c"
+                "url": "https://github.com/doctrine/annotations.git",
+                "reference": "54cacc9b81758b14e3ce750f205a393d52339e97"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c",
-                "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c",
+                "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97",
+                "reference": "54cacc9b81758b14e3ce750f205a393d52339e97",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.2"
+                "doctrine/lexer": "1.*",
+                "php": "^5.6 || ^7.0"
+            },
+            "require-dev": {
+                "doctrine/cache": "1.*",
+                "phpunit/phpunit": "^5.7"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0.x-dev"
+                    "dev-master": "1.4.x-dev"
                 }
             },
             "autoload": {
-                "psr-0": {
-                    "Doctrine\\Common\\Lexer\\": "lib/"
+                "psr-4": {
+                    "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -43,58 +48,66 @@
                     "name": "Roman Borschel",
                     "email": "roman@code-factory.org"
                 },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
                 {
                     "name": "Guilherme Blanco",
                     "email": "guilhermeblanco@gmail.com"
                 },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
                 {
                     "name": "Johannes Schmitt",
                     "email": "schmittjoh@gmail.com"
                 }
             ],
-            "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
+            "description": "Docblock Annotations Parser",
             "homepage": "http://www.doctrine-project.org",
             "keywords": [
-                "lexer",
+                "annotations",
+                "docblock",
                 "parser"
             ],
-            "time": "2014-09-09T13:34:57+00:00"
+            "time": "2017-02-24T16:22:25+00:00"
         },
         {
-            "name": "egulias/email-validator",
-            "version": "2.1.3",
+            "name": "doctrine/cache",
+            "version": "v1.6.2",
             "source": {
                 "type": "git",
-                "url": "https://github.com/egulias/EmailValidator.git",
-                "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04"
+                "url": "https://github.com/doctrine/cache.git",
+                "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/1bec00a10039b823cc94eef4eddd47dcd3b2ca04",
-                "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04",
+                "url": "https://api.github.com/repos/doctrine/cache/zipball/eb152c5100571c7a45470ff2a35095ab3f3b900b",
+                "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b",
                 "shasum": ""
             },
             "require": {
-                "doctrine/lexer": "^1.0.1",
-                "php": ">= 5.5"
+                "php": "~5.5|~7.0"
             },
-            "require-dev": {
-                "dominicsayers/isemail": "dev-master",
-                "phpunit/phpunit": "^4.8.35",
-                "satooshi/php-coveralls": "^1.0.1"
+            "conflict": {
+                "doctrine/common": ">2.2,<2.4"
             },
-            "suggest": {
-                "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
+            "require-dev": {
+                "phpunit/phpunit": "~4.8|~5.0",
+                "predis/predis": "~1.0",
+                "satooshi/php-coveralls": "~0.6"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "2.0.x-dev"
+                    "dev-master": "1.6.x-dev"
                 }
             },
             "autoload": {
                 "psr-4": {
-                    "Egulias\\EmailValidator\\": "EmailValidator"
+                    "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -103,45 +116,64 @@
             ],
             "authors": [
                 {
-                    "name": "Eduardo Gulias Davis"
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
                 }
             ],
-            "description": "A library for validating emails against several RFCs",
-            "homepage": "https://github.com/egulias/EmailValidator",
+            "description": "Caching library offering an object-oriented API for many cache backends",
+            "homepage": "http://www.doctrine-project.org",
             "keywords": [
-                "email",
-                "emailvalidation",
-                "emailvalidator",
-                "validation",
-                "validator"
+                "cache",
+                "caching"
             ],
-            "time": "2017-11-15T23:40:40+00:00"
+            "time": "2017-07-22T12:49:21+00:00"
         },
         {
-            "name": "erusev/parsedown",
-            "version": "1.7.1",
+            "name": "doctrine/collections",
+            "version": "v1.4.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/erusev/parsedown.git",
-                "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1"
+                "url": "https://github.com/doctrine/collections.git",
+                "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/erusev/parsedown/zipball/92e9c27ba0e74b8b028b111d1b6f956a15c01fc1",
-                "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1",
+                "url": "https://api.github.com/repos/doctrine/collections/zipball/1a4fb7e902202c33cce8c55989b945612943c2ba",
+                "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba",
                 "shasum": ""
             },
             "require": {
-                "ext-mbstring": "*",
-                "php": ">=5.3.0"
+                "php": "^5.6 || ^7.0"
             },
             "require-dev": {
-                "phpunit/phpunit": "^4.8.35"
+                "doctrine/coding-standard": "~0.1@dev",
+                "phpunit/phpunit": "^5.7"
             },
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.3.x-dev"
+                }
+            },
             "autoload": {
                 "psr-0": {
-                    "Parsedown": ""
+                    "Doctrine\\Common\\Collections\\": "lib/"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -150,41 +182,70 @@
             ],
             "authors": [
                 {
-                    "name": "Emanuil Rusev",
-                    "email": "hello@erusev.com",
-                    "homepage": "http://erusev.com"
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
                 }
             ],
-            "description": "Parser for Markdown.",
-            "homepage": "http://parsedown.org",
+            "description": "Collections Abstraction library",
+            "homepage": "http://www.doctrine-project.org",
             "keywords": [
-                "markdown",
-                "parser"
+                "array",
+                "collections",
+                "iterator"
             ],
-            "time": "2018-03-08T01:11:30+00:00"
+            "time": "2017-01-03T10:49:41+00:00"
         },
         {
-            "name": "ircmaxell/password-compat",
-            "version": "dev-master",
+            "name": "doctrine/common",
+            "version": "v2.7.3",
             "source": {
                 "type": "git",
-                "url": "https://github.com/ircmaxell/password_compat.git",
-                "reference": "dfdbc467fba0d1db4c2f51fda58e1717046f3284"
+                "url": "https://github.com/doctrine/common.git",
+                "reference": "4acb8f89626baafede6ee5475bc5844096eba8a9"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/dfdbc467fba0d1db4c2f51fda58e1717046f3284",
-                "reference": "dfdbc467fba0d1db4c2f51fda58e1717046f3284",
+                "url": "https://api.github.com/repos/doctrine/common/zipball/4acb8f89626baafede6ee5475bc5844096eba8a9",
+                "reference": "4acb8f89626baafede6ee5475bc5844096eba8a9",
                 "shasum": ""
             },
+            "require": {
+                "doctrine/annotations": "1.*",
+                "doctrine/cache": "1.*",
+                "doctrine/collections": "1.*",
+                "doctrine/inflector": "1.*",
+                "doctrine/lexer": "1.*",
+                "php": "~5.6|~7.0"
+            },
             "require-dev": {
-                "phpunit/phpunit": "4.*"
+                "phpunit/phpunit": "^5.4.6"
             },
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.7.x-dev"
+                }
+            },
             "autoload": {
-                "files": [
-                    "lib/password.php"
-                ]
+                "psr-4": {
+                    "Doctrine\\Common\\": "lib/Doctrine/Common"
+                }
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
@@ -192,110 +253,602 @@
             ],
             "authors": [
                 {
-                    "name": "Anthony Ferrara",
-                    "email": "ircmaxell@php.net",
-                    "homepage": "http://blog.ircmaxell.com"
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
                 }
             ],
-            "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash",
-            "homepage": "https://github.com/ircmaxell/password_compat",
+            "description": "Common Library for Doctrine projects",
+            "homepage": "http://www.doctrine-project.org",
             "keywords": [
-                "hashing",
-                "password"
+                "annotations",
+                "collections",
+                "eventmanager",
+                "persistence",
+                "spl"
             ],
-            "time": "2017-03-20T21:17:32+00:00"
+            "time": "2017-07-22T08:35:12+00:00"
         },
         {
-            "name": "o80/i18n",
-            "version": "dev-develop",
+            "name": "doctrine/dbal",
+            "version": "v2.5.13",
             "source": {
                 "type": "git",
-                "url": "https://github.com/olivierperez/o80-i18n.git",
-                "reference": "8f3fbc7c965559802ed4eda602528a24d641ea15"
+                "url": "https://github.com/doctrine/dbal.git",
+                "reference": "729340d8d1eec8f01bff708e12e449a3415af873"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/olivierperez/o80-i18n/zipball/8f3fbc7c965559802ed4eda602528a24d641ea15",
-                "reference": "8f3fbc7c965559802ed4eda602528a24d641ea15",
+                "url": "https://api.github.com/repos/doctrine/dbal/zipball/729340d8d1eec8f01bff708e12e449a3415af873",
+                "reference": "729340d8d1eec8f01bff708e12e449a3415af873",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.3.0"
+                "doctrine/common": ">=2.4,<2.8-dev",
+                "php": ">=5.3.2"
             },
             "require-dev": {
-                "phpunit/phpunit": "^4.5"
+                "phpunit/phpunit": "4.*",
+                "symfony/console": "2.*||^3.0"
+            },
+            "suggest": {
+                "symfony/console": "For helpful console commands such as SQL execution and import of files."
             },
+            "bin": [
+                "bin/doctrine-dbal"
+            ],
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.5.x-dev"
+                }
+            },
             "autoload": {
-                "psr-4": {
-                    "o80\\": "src/o80"
+                "psr-0": {
+                    "Doctrine\\DBAL\\": "lib/"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
-                "Apache License 2.0"
+                "MIT"
             ],
             "authors": [
                 {
-                    "name": "Olivier Perez",
-                    "email": "olivier@olivierperez.fr",
-                    "homepage": "http://github.com/olivierperez"
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
                 }
             ],
-            "description": "Easy library to manage i18n with PHP.",
-            "homepage": "https://github.com/olivierperez/o80-i18n",
+            "description": "Database Abstraction Layer",
+            "homepage": "http://www.doctrine-project.org",
             "keywords": [
-                "i18n",
-                "internationalization",
-                "php"
+                "database",
+                "dbal",
+                "persistence",
+                "queryobject"
             ],
-            "time": "2015-09-21T21:18:45+00:00"
+            "time": "2017-07-22T20:44:48+00:00"
         },
         {
-            "name": "phpmailer/phpmailer",
-            "version": "v5.2.26",
+            "name": "doctrine/inflector",
+            "version": "v1.1.0",
             "source": {
                 "type": "git",
-                "url": "https://github.com/PHPMailer/PHPMailer.git",
-                "reference": "70362997bda4376378be7d92d81e2200550923f7"
+                "url": "https://github.com/doctrine/inflector.git",
+                "reference": "90b2128806bfde671b6952ab8bea493942c1fdae"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/70362997bda4376378be7d92d81e2200550923f7",
-                "reference": "70362997bda4376378be7d92d81e2200550923f7",
+                "url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae",
+                "reference": "90b2128806bfde671b6952ab8bea493942c1fdae",
                 "shasum": ""
             },
             "require": {
-                "ext-ctype": "*",
-                "php": ">=5.0.0"
+                "php": ">=5.3.2"
             },
             "require-dev": {
-                "doctrine/annotations": "1.2.*",
-                "jms/serializer": "0.16.*",
-                "phpdocumentor/phpdocumentor": "2.*",
-                "phpunit/phpunit": "4.8.*",
-                "symfony/debug": "2.8.*",
-                "symfony/filesystem": "2.8.*",
-                "symfony/translation": "2.8.*",
-                "symfony/yaml": "2.8.*",
-                "zendframework/zend-cache": "2.5.1",
-                "zendframework/zend-config": "2.5.1",
-                "zendframework/zend-eventmanager": "2.5.1",
-                "zendframework/zend-filter": "2.5.1",
-                "zendframework/zend-i18n": "2.5.1",
-                "zendframework/zend-json": "2.5.1",
-                "zendframework/zend-math": "2.5.1",
-                "zendframework/zend-serializer": "2.5.*",
-                "zendframework/zend-servicemanager": "2.5.*",
-                "zendframework/zend-stdlib": "2.5.1"
-            },
-            "suggest": {
-                "league/oauth2-google": "Needed for Google XOAUTH2 authentication"
+                "phpunit/phpunit": "4.*"
             },
             "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1.x-dev"
+                }
+            },
             "autoload": {
-                "classmap": [
-                    "class.phpmailer.php",
+                "psr-0": {
+                    "Doctrine\\Common\\Inflector\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
+                }
+            ],
+            "description": "Common String Manipulations with regard to casing and singular/plural rules.",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "inflection",
+                "pluralize",
+                "singularize",
+                "string"
+            ],
+            "time": "2015-11-06T14:35:42+00:00"
+        },
+        {
+            "name": "doctrine/lexer",
+            "version": "v1.0.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/lexer.git",
+                "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c",
+                "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "Doctrine\\Common\\Lexer\\": "lib/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Roman Borschel",
+                    "email": "roman@code-factory.org"
+                },
+                {
+                    "name": "Guilherme Blanco",
+                    "email": "guilhermeblanco@gmail.com"
+                },
+                {
+                    "name": "Johannes Schmitt",
+                    "email": "schmittjoh@gmail.com"
+                }
+            ],
+            "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "lexer",
+                "parser"
+            ],
+            "time": "2014-09-09T13:34:57+00:00"
+        },
+        {
+            "name": "doctrine/migrations",
+            "version": "v1.5.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/doctrine/migrations.git",
+                "reference": "c81147c0f2938a6566594455367e095150547f72"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/doctrine/migrations/zipball/c81147c0f2938a6566594455367e095150547f72",
+                "reference": "c81147c0f2938a6566594455367e095150547f72",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/dbal": "~2.2",
+                "ocramius/proxy-manager": "^1.0|^2.0",
+                "php": "^5.5|^7.0",
+                "symfony/console": "~2.3|~3.0",
+                "symfony/yaml": "~2.3|~3.0"
+            },
+            "require-dev": {
+                "doctrine/coding-standard": "dev-master",
+                "doctrine/orm": "2.*",
+                "jdorn/sql-formatter": "~1.1",
+                "johnkary/phpunit-speedtrap": "~1.0@dev",
+                "mikey179/vfsstream": "^1.6",
+                "mockery/mockery": "^0.9.4",
+                "phpunit/phpunit": "~4.7",
+                "satooshi/php-coveralls": "^1.0"
+            },
+            "suggest": {
+                "jdorn/sql-formatter": "Allows to generate formatted SQL with the diff command."
+            },
+            "bin": [
+                "bin/doctrine-migrations"
+            ],
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "v1.6.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Doctrine\\DBAL\\Migrations\\": "lib/Doctrine/DBAL/Migrations"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1"
+            ],
+            "authors": [
+                {
+                    "name": "Benjamin Eberlei",
+                    "email": "kontakt@beberlei.de"
+                },
+                {
+                    "name": "Jonathan Wage",
+                    "email": "jonwage@gmail.com"
+                },
+                {
+                    "name": "Michael Simonson",
+                    "email": "contact@mikesimonson.com"
+                }
+            ],
+            "description": "Database Schema migrations using Doctrine DBAL",
+            "homepage": "http://www.doctrine-project.org",
+            "keywords": [
+                "database",
+                "migrations"
+            ],
+            "time": "2016-12-25T22:54:00+00:00"
+        },
+        {
+            "name": "egulias/email-validator",
+            "version": "2.1.4",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/egulias/EmailValidator.git",
+                "reference": "8790f594151ca6a2010c6218e09d96df67173ad3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/8790f594151ca6a2010c6218e09d96df67173ad3",
+                "reference": "8790f594151ca6a2010c6218e09d96df67173ad3",
+                "shasum": ""
+            },
+            "require": {
+                "doctrine/lexer": "^1.0.1",
+                "php": ">= 5.5"
+            },
+            "require-dev": {
+                "dominicsayers/isemail": "dev-master",
+                "phpunit/phpunit": "^4.8.35||^5.7||^6.0",
+                "satooshi/php-coveralls": "^1.0.1"
+            },
+            "suggest": {
+                "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Egulias\\EmailValidator\\": "EmailValidator"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Eduardo Gulias Davis"
+                }
+            ],
+            "description": "A library for validating emails against several RFCs",
+            "homepage": "https://github.com/egulias/EmailValidator",
+            "keywords": [
+                "email",
+                "emailvalidation",
+                "emailvalidator",
+                "validation",
+                "validator"
+            ],
+            "time": "2018-04-10T10:11:19+00:00"
+        },
+        {
+            "name": "erusev/parsedown",
+            "version": "1.7.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/erusev/parsedown.git",
+                "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/erusev/parsedown/zipball/92e9c27ba0e74b8b028b111d1b6f956a15c01fc1",
+                "reference": "92e9c27ba0e74b8b028b111d1b6f956a15c01fc1",
+                "shasum": ""
+            },
+            "require": {
+                "ext-mbstring": "*",
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8.35"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Parsedown": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Emanuil Rusev",
+                    "email": "hello@erusev.com",
+                    "homepage": "http://erusev.com"
+                }
+            ],
+            "description": "Parser for Markdown.",
+            "homepage": "http://parsedown.org",
+            "keywords": [
+                "markdown",
+                "parser"
+            ],
+            "time": "2018-03-08T01:11:30+00:00"
+        },
+        {
+            "name": "ircmaxell/password-compat",
+            "version": "dev-master",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ircmaxell/password_compat.git",
+                "reference": "dfdbc467fba0d1db4c2f51fda58e1717046f3284"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/dfdbc467fba0d1db4c2f51fda58e1717046f3284",
+                "reference": "dfdbc467fba0d1db4c2f51fda58e1717046f3284",
+                "shasum": ""
+            },
+            "require-dev": {
+                "phpunit/phpunit": "4.*"
+            },
+            "type": "library",
+            "autoload": {
+                "files": [
+                    "lib/password.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Anthony Ferrara",
+                    "email": "ircmaxell@php.net",
+                    "homepage": "http://blog.ircmaxell.com"
+                }
+            ],
+            "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash",
+            "homepage": "https://github.com/ircmaxell/password_compat",
+            "keywords": [
+                "hashing",
+                "password"
+            ],
+            "time": "2017-03-20T21:17:32+00:00"
+        },
+        {
+            "name": "o80/i18n",
+            "version": "dev-develop",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/olivierperez/o80-i18n.git",
+                "reference": "8f3fbc7c965559802ed4eda602528a24d641ea15"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/olivierperez/o80-i18n/zipball/8f3fbc7c965559802ed4eda602528a24d641ea15",
+                "reference": "8f3fbc7c965559802ed4eda602528a24d641ea15",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.5"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "o80\\": "src/o80"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "Apache License 2.0"
+            ],
+            "authors": [
+                {
+                    "name": "Olivier Perez",
+                    "email": "olivier@olivierperez.fr",
+                    "homepage": "http://github.com/olivierperez"
+                }
+            ],
+            "description": "Easy library to manage i18n with PHP.",
+            "homepage": "https://github.com/olivierperez/o80-i18n",
+            "keywords": [
+                "i18n",
+                "internationalization",
+                "php"
+            ],
+            "time": "2015-09-21T21:18:45+00:00"
+        },
+        {
+            "name": "ocramius/proxy-manager",
+            "version": "1.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Ocramius/ProxyManager.git",
+                "reference": "57e9272ec0e8deccf09421596e0e2252df440e11"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Ocramius/ProxyManager/zipball/57e9272ec0e8deccf09421596e0e2252df440e11",
+                "reference": "57e9272ec0e8deccf09421596e0e2252df440e11",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3",
+                "zendframework/zend-code": ">2.2.5,<3.0"
+            },
+            "require-dev": {
+                "ext-phar": "*",
+                "phpunit/phpunit": "~4.0",
+                "squizlabs/php_codesniffer": "1.5.*"
+            },
+            "suggest": {
+                "ocramius/generated-hydrator": "To have very fast object to array to object conversion for ghost objects",
+                "zendframework/zend-json": "To have the JsonRpc adapter (Remote Object feature)",
+                "zendframework/zend-soap": "To have the Soap adapter (Remote Object feature)",
+                "zendframework/zend-stdlib": "To use the hydrator proxy",
+                "zendframework/zend-xmlrpc": "To have the XmlRpc adapter (Remote Object feature)"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "ProxyManager\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Marco Pivetta",
+                    "email": "ocramius@gmail.com",
+                    "homepage": "http://ocramius.github.com/"
+                }
+            ],
+            "description": "A library providing utilities to generate, instantiate and generally operate with Object Proxies",
+            "homepage": "https://github.com/Ocramius/ProxyManager",
+            "keywords": [
+                "aop",
+                "lazy loading",
+                "proxy",
+                "proxy pattern",
+                "service proxies"
+            ],
+            "time": "2015-08-09T04:28:19+00:00"
+        },
+        {
+            "name": "phpmailer/phpmailer",
+            "version": "v5.2.26",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/PHPMailer/PHPMailer.git",
+                "reference": "70362997bda4376378be7d92d81e2200550923f7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/70362997bda4376378be7d92d81e2200550923f7",
+                "reference": "70362997bda4376378be7d92d81e2200550923f7",
+                "shasum": ""
+            },
+            "require": {
+                "ext-ctype": "*",
+                "php": ">=5.0.0"
+            },
+            "require-dev": {
+                "doctrine/annotations": "1.2.*",
+                "jms/serializer": "0.16.*",
+                "phpdocumentor/phpdocumentor": "2.*",
+                "phpunit/phpunit": "4.8.*",
+                "symfony/debug": "2.8.*",
+                "symfony/filesystem": "2.8.*",
+                "symfony/translation": "2.8.*",
+                "symfony/yaml": "2.8.*",
+                "zendframework/zend-cache": "2.5.1",
+                "zendframework/zend-config": "2.5.1",
+                "zendframework/zend-eventmanager": "2.5.1",
+                "zendframework/zend-filter": "2.5.1",
+                "zendframework/zend-i18n": "2.5.1",
+                "zendframework/zend-json": "2.5.1",
+                "zendframework/zend-math": "2.5.1",
+                "zendframework/zend-serializer": "2.5.*",
+                "zendframework/zend-servicemanager": "2.5.*",
+                "zendframework/zend-stdlib": "2.5.1"
+            },
+            "suggest": {
+                "league/oauth2-google": "Needed for Google XOAUTH2 authentication"
+            },
+            "type": "library",
+            "autoload": {
+                "classmap": [
+                    "class.phpmailer.php",
                     "class.phpmaileroauth.php",
                     "class.phpmaileroauthgoogle.php",
                     "class.smtp.php",
@@ -325,8 +878,55 @@
                     "name": "Brent R. Matzelle"
                 }
             ],
-            "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
-            "time": "2017-11-04T09:26:05+00:00"
+            "description": "PHPMailer is a full-featured email creation and transfer class for PHP",
+            "time": "2017-11-04T09:26:05+00:00"
+        },
+        {
+            "name": "psr/log",
+            "version": "1.0.2",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/log.git",
+                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
+                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Log\\": "Psr/Log/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for logging libraries",
+            "homepage": "https://github.com/php-fig/log",
+            "keywords": [
+                "log",
+                "psr",
+                "psr-3"
+            ],
+            "time": "2016-10-10T12:19:37+00:00"
         },
         {
             "name": "roave/security-advisories",
@@ -334,12 +934,12 @@
             "source": {
                 "type": "git",
                 "url": "https://github.com/Roave/SecurityAdvisories.git",
-                "reference": "1b2f1f59ff8fc933e4d61ee45214ff3228e20c75"
+                "reference": "2b28787651b69de2b14ae222737deb05befbb33b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/1b2f1f59ff8fc933e4d61ee45214ff3228e20c75",
-                "reference": "1b2f1f59ff8fc933e4d61ee45214ff3228e20c75",
+                "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/2b28787651b69de2b14ae222737deb05befbb33b",
+                "reference": "2b28787651b69de2b14ae222737deb05befbb33b",
                 "shasum": ""
             },
             "conflict": {
@@ -356,8 +956,8 @@
                 "codeigniter/framework": "<=3.0.6",
                 "composer/composer": "<=1.0.0-alpha11",
                 "contao-components/mediaelement": ">=2.14.2,<2.21.1",
-                "contao/core": ">=2,<3.5.32",
-                "contao/core-bundle": ">=4,<4.4.8",
+                "contao/core": ">=2,<3.5.35",
+                "contao/core-bundle": ">=4,<4.4.18|>=4.5,<4.5.8",
                 "contao/listing-bundle": ">=4,<4.4.8",
                 "contao/newsletter-bundle": ">=4,<4.1",
                 "doctrine/annotations": ">=1,<1.2.7",
@@ -370,8 +970,8 @@
                 "doctrine/mongodb-odm-bundle": ">=2,<3.0.1",
                 "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1",
                 "dompdf/dompdf": ">=0.6,<0.6.2",
-                "drupal/core": ">=8,<8.4.5",
-                "drupal/drupal": ">=8,<8.4.5",
+                "drupal/core": ">=7,<7.58|>=8,<8.4.6|>=8.5,<8.5.1",
+                "drupal/drupal": ">=7,<7.58|>=8,<8.4.6|>=8.5,<8.5.1",
                 "erusev/parsedown": "<1.7",
                 "ezsystems/ezpublish-legacy": ">=5.3,<5.3.12.3|>=5.4,<5.4.11.3|>=2017.8,<2017.8.1.1|>=2017.12,<2017.12.2.1",
                 "firebase/php-jwt": "<2",
@@ -380,10 +980,12 @@
                 "gree/jose": "<=2.2",
                 "gregwar/rst": "<1.0.3",
                 "guzzlehttp/guzzle": ">=6,<6.2.1|>=4.0.0-rc2,<4.2.4|>=5,<5.3.1",
-                "illuminate/auth": ">=4,<4.0.99|>=4.1,<4.1.26",
+                "illuminate/auth": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.10",
                 "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29",
+                "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15",
                 "joomla/session": "<1.3.1",
-                "laravel/framework": ">=4,<4.0.99|>=4.1,<4.1.29",
+                "kreait/firebase-php": ">=3.2,<3.8.1",
+                "laravel/framework": ">=4,<4.0.99|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15",
                 "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10",
                 "magento/magento1ce": ">=1.5.0.1,<1.9.3.2",
                 "magento/magento1ee": ">=1.9,<1.14.3.2",
@@ -396,6 +998,7 @@
                 "padraic/humbug_get_contents": "<1.1.2",
                 "pagarme/pagarme-php": ">=0,<3",
                 "paragonie/random_compat": "<2",
+                "paypal/merchant-sdk-php": "<3.12",
                 "phpmailer/phpmailer": ">=5,<5.2.24",
                 "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3",
                 "phpxmlrpc/extras": "<0.6.1",
@@ -411,8 +1014,9 @@
                 "simplesamlphp/saml2": "<1.10.6|>=2,<2.3.8|>=3,<3.1.4",
                 "simplesamlphp/simplesamlphp": "<1.15.2",
                 "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1",
+                "slim/slim": "<2.6",
                 "socalnick/scn-social-auth": "<1.15.2",
-                "squizlabs/php_codesniffer": ">=1,<2.8.1",
+                "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1",
                 "stormpath/sdk": ">=0,<9.9.99",
                 "swiftmailer/swiftmailer": ">=4,<5.4.5",
                 "symfony/dependency-injection": ">=2,<2.0.17",
@@ -433,7 +1037,7 @@
                 "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4",
                 "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7",
                 "thelia/backoffice-default-template": ">=2.1,<2.1.2",
-                "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2",
+                "thelia/thelia": ">=2.1,<2.1.2|>=2.1.0-beta1,<2.1.3",
                 "titon/framework": ">=0,<9.9.99",
                 "twig/twig": "<1.20",
                 "typo3/cms": ">=6.2,<6.2.30|>=7,<7.6.22|>=8,<8.7.5",
@@ -441,11 +1045,13 @@
                 "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4",
                 "willdurand/js-translation-bundle": "<2.1.1",
                 "yiisoft/yii": ">=1.1.14,<1.1.15",
-                "yiisoft/yii2": "<2.0.14",
+                "yiisoft/yii2": "<2.0.15",
                 "yiisoft/yii2-bootstrap": "<2.0.4",
-                "yiisoft/yii2-dev": "<2.0.14",
+                "yiisoft/yii2-dev": "<2.0.15",
+                "yiisoft/yii2-elasticsearch": "<2.0.5",
                 "yiisoft/yii2-gii": "<2.0.4",
                 "yiisoft/yii2-jui": "<2.0.4",
+                "yiisoft/yii2-redis": "<2.0.8",
                 "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3",
                 "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2",
                 "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2",
@@ -470,73 +1076,465 @@
                 "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3",
                 "zfr/zfr-oauth2-server-module": "<0.1.2"
             },
-            "type": "metapackage",
+            "type": "metapackage",
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Marco Pivetta",
+                    "email": "ocramius@gmail.com",
+                    "role": "maintainer"
+                }
+            ],
+            "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it",
+            "time": "2018-04-18T09:24:34+00:00"
+        },
+        {
+            "name": "sensiolabs/ansi-to-html",
+            "version": "v1.1.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/sensiolabs/ansi-to-html.git",
+                "reference": "8b5d787dca714bd98dd770c078d76528320a8286"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/sensiolabs/ansi-to-html/zipball/8b5d787dca714bd98dd770c078d76528320a8286",
+                "reference": "8b5d787dca714bd98dd770c078d76528320a8286",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "suggest": {
+                "twig/twig": "Provides nice templating features"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.1-dev"
+                }
+            },
+            "autoload": {
+                "psr-0": {
+                    "SensioLabs\\AnsiConverter": "."
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                }
+            ],
+            "description": "A library to convert a text with ANSI codes to HTML",
+            "time": "2017-05-02T00:53:29+00:00"
+        },
+        {
+            "name": "smarty/smarty",
+            "version": "v3.1.31",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/smarty-php/smarty.git",
+                "reference": "c7d42e4a327c402897dd587871434888fde1e7a9"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/smarty-php/smarty/zipball/c7d42e4a327c402897dd587871434888fde1e7a9",
+                "reference": "c7d42e4a327c402897dd587871434888fde1e7a9",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.2"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.1.x-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "libs/bootstrap.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-3.0"
+            ],
+            "authors": [
+                {
+                    "name": "Monte Ohrt",
+                    "email": "monte@ohrt.com"
+                },
+                {
+                    "name": "Uwe Tews",
+                    "email": "uwe.tews@googlemail.com"
+                },
+                {
+                    "name": "Rodney Rehm",
+                    "email": "rodney.rehm@medialize.de"
+                }
+            ],
+            "description": "Smarty - the compiling PHP template engine",
+            "homepage": "http://www.smarty.net",
+            "keywords": [
+                "templating"
+            ],
+            "time": "2016-12-14T21:57:25+00:00"
+        },
+        {
+            "name": "symfony/console",
+            "version": "v3.4.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/console.git",
+                "reference": "d4bb70fa24d540c309d88a9d6e43fb2d339b1fbf"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/console/zipball/d4bb70fa24d540c309d88a9d6e43fb2d339b1fbf",
+                "reference": "d4bb70fa24d540c309d88a9d6e43fb2d339b1fbf",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5.9|>=7.0.8",
+                "symfony/debug": "~2.8|~3.0|~4.0",
+                "symfony/polyfill-mbstring": "~1.0"
+            },
+            "conflict": {
+                "symfony/dependency-injection": "<3.4",
+                "symfony/process": "<3.3"
+            },
+            "require-dev": {
+                "psr/log": "~1.0",
+                "symfony/config": "~3.3|~4.0",
+                "symfony/dependency-injection": "~3.4|~4.0",
+                "symfony/event-dispatcher": "~2.8|~3.0|~4.0",
+                "symfony/lock": "~3.4|~4.0",
+                "symfony/process": "~3.3|~4.0"
+            },
+            "suggest": {
+                "psr/log": "For using the console logger",
+                "symfony/event-dispatcher": "",
+                "symfony/lock": "",
+                "symfony/process": ""
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Console\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Console Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-04-03T05:22:50+00:00"
+        },
+        {
+            "name": "symfony/debug",
+            "version": "v3.4.8",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/debug.git",
+                "reference": "9cf7c2271cfb89ef9727db1b740ca77be57bf9d7"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/debug/zipball/9cf7c2271cfb89ef9727db1b740ca77be57bf9d7",
+                "reference": "9cf7c2271cfb89ef9727db1b740ca77be57bf9d7",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5.9|>=7.0.8",
+                "psr/log": "~1.0"
+            },
+            "conflict": {
+                "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
+            },
+            "require-dev": {
+                "symfony/http-kernel": "~2.8|~3.0|~4.0"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.4-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Component\\Debug\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony Debug Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-04-03T05:22:50+00:00"
+        },
+        {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.7.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
+                "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.3"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.7-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                },
+                "files": [
+                    "bootstrap.php"
+                ]
+            },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
                 "MIT"
             ],
             "authors": [
                 {
-                    "name": "Marco Pivetta",
-                    "email": "ocramius@gmail.com",
-                    "role": "maintainer"
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it",
-            "time": "2018-03-15T17:53:05+00:00"
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "time": "2018-01-30T19:27:44+00:00"
         },
         {
-            "name": "smarty/smarty",
-            "version": "v3.1.31",
+            "name": "symfony/yaml",
+            "version": "v3.4.8",
             "source": {
                 "type": "git",
-                "url": "https://github.com/smarty-php/smarty.git",
-                "reference": "c7d42e4a327c402897dd587871434888fde1e7a9"
+                "url": "https://github.com/symfony/yaml.git",
+                "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/smarty-php/smarty/zipball/c7d42e4a327c402897dd587871434888fde1e7a9",
-                "reference": "c7d42e4a327c402897dd587871434888fde1e7a9",
+                "url": "https://api.github.com/repos/symfony/yaml/zipball/a42f9da85c7c38d59f5e53f076fe81a091f894d0",
+                "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0",
                 "shasum": ""
             },
             "require": {
-                "php": ">=5.2"
+                "php": "^5.5.9|>=7.0.8"
+            },
+            "conflict": {
+                "symfony/console": "<3.4"
+            },
+            "require-dev": {
+                "symfony/console": "~3.4|~4.0"
+            },
+            "suggest": {
+                "symfony/console": "For validating YAML files using the lint command"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "3.1.x-dev"
+                    "dev-master": "3.4-dev"
                 }
             },
             "autoload": {
-                "files": [
-                    "libs/bootstrap.php"
+                "psr-4": {
+                    "Symfony\\Component\\Yaml\\": ""
+                },
+                "exclude-from-classmap": [
+                    "/Tests/"
                 ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
-                "LGPL-3.0"
+                "MIT"
             ],
             "authors": [
                 {
-                    "name": "Monte Ohrt",
-                    "email": "monte@ohrt.com"
-                },
-                {
-                    "name": "Uwe Tews",
-                    "email": "uwe.tews@googlemail.com"
+                    "name": "Fabien Potencier",
+                    "email": "fabien@symfony.com"
                 },
                 {
-                    "name": "Rodney Rehm",
-                    "email": "rodney.rehm@medialize.de"
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
                 }
             ],
-            "description": "Smarty - the compiling PHP template engine",
-            "homepage": "http://www.smarty.net",
+            "description": "Symfony Yaml Component",
+            "homepage": "https://symfony.com",
+            "time": "2018-04-03T05:14:20+00:00"
+        },
+        {
+            "name": "zendframework/zend-code",
+            "version": "2.6.3",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/zendframework/zend-code.git",
+                "reference": "95033f061b083e16cdee60530ec260d7d628b887"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/zendframework/zend-code/zipball/95033f061b083e16cdee60530ec260d7d628b887",
+                "reference": "95033f061b083e16cdee60530ec260d7d628b887",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.5 || 7.0.0 - 7.0.4 || ^7.0.6",
+                "zendframework/zend-eventmanager": "^2.6 || ^3.0"
+            },
+            "require-dev": {
+                "doctrine/annotations": "~1.0",
+                "fabpot/php-cs-fixer": "1.7.*",
+                "phpunit/phpunit": "^4.8.21",
+                "zendframework/zend-stdlib": "^2.7 || ^3.0"
+            },
+            "suggest": {
+                "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features",
+                "zendframework/zend-stdlib": "Zend\\Stdlib component"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.6-dev",
+                    "dev-develop": "2.7-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Zend\\Code\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "description": "provides facilities to generate arbitrary code using an object oriented interface",
+            "homepage": "https://github.com/zendframework/zend-code",
             "keywords": [
-                "templating"
+                "code",
+                "zf2"
             ],
-            "time": "2016-12-14T21:57:25+00:00"
+            "time": "2016-04-20T17:26:42+00:00"
+        },
+        {
+            "name": "zendframework/zend-eventmanager",
+            "version": "3.2.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/zendframework/zend-eventmanager.git",
+                "reference": "9d72db10ceb6e42fb92350c0cb54460da61bd79c"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/9d72db10ceb6e42fb92350c0cb54460da61bd79c",
+                "reference": "9d72db10ceb6e42fb92350c0cb54460da61bd79c",
+                "shasum": ""
+            },
+            "require": {
+                "php": "^5.6 || ^7.0"
+            },
+            "require-dev": {
+                "athletic/athletic": "^0.1",
+                "container-interop/container-interop": "^1.1.0",
+                "phpunit/phpunit": "^6.0.7 || ^5.7.14",
+                "zendframework/zend-coding-standard": "~1.0.0",
+                "zendframework/zend-stdlib": "^2.7.3 || ^3.0"
+            },
+            "suggest": {
+                "container-interop/container-interop": "^1.1.0, to use the lazy listeners feature",
+                "zendframework/zend-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "3.2-dev",
+                    "dev-develop": "3.3-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Zend\\EventManager\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "BSD-3-Clause"
+            ],
+            "description": "Trigger and listen to events within a PHP application",
+            "homepage": "https://github.com/zendframework/zend-eventmanager",
+            "keywords": [
+                "event",
+                "eventmanager",
+                "events",
+                "zf2"
+            ],
+            "time": "2017-07-11T19:17:22+00:00"
         }
     ],
     "packages-dev": [
@@ -602,74 +1600,6 @@
             ],
             "time": "2016-08-30T16:08:34+00:00"
         },
-        {
-            "name": "doctrine/annotations",
-            "version": "v1.4.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/doctrine/annotations.git",
-                "reference": "54cacc9b81758b14e3ce750f205a393d52339e97"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97",
-                "reference": "54cacc9b81758b14e3ce750f205a393d52339e97",
-                "shasum": ""
-            },
-            "require": {
-                "doctrine/lexer": "1.*",
-                "php": "^5.6 || ^7.0"
-            },
-            "require-dev": {
-                "doctrine/cache": "1.*",
-                "phpunit/phpunit": "^5.7"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.4.x-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations"
-                }
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Roman Borschel",
-                    "email": "roman@code-factory.org"
-                },
-                {
-                    "name": "Benjamin Eberlei",
-                    "email": "kontakt@beberlei.de"
-                },
-                {
-                    "name": "Guilherme Blanco",
-                    "email": "guilhermeblanco@gmail.com"
-                },
-                {
-                    "name": "Jonathan Wage",
-                    "email": "jonwage@gmail.com"
-                },
-                {
-                    "name": "Johannes Schmitt",
-                    "email": "schmittjoh@gmail.com"
-                }
-            ],
-            "description": "Docblock Annotations Parser",
-            "homepage": "http://www.doctrine-project.org",
-            "keywords": [
-                "annotations",
-                "docblock",
-                "parser"
-            ],
-            "time": "2017-02-24T16:22:25+00:00"
-        },
         {
             "name": "doctrine/instantiator",
             "version": "1.0.5",
@@ -726,16 +1656,16 @@
         },
         {
             "name": "friendsofphp/php-cs-fixer",
-            "version": "v2.10.4",
+            "version": "v2.11.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git",
-                "reference": "b2dce1dacff988b79c4aadf252e5dee31bc04e19"
+                "reference": "ad94441c17b8ef096e517acccdbf3238af8a2da8"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/b2dce1dacff988b79c4aadf252e5dee31bc04e19",
-                "reference": "b2dce1dacff988b79c4aadf252e5dee31bc04e19",
+                "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/ad94441c17b8ef096e517acccdbf3238af8a2da8",
+                "reference": "ad94441c17b8ef096e517acccdbf3238af8a2da8",
                 "shasum": ""
             },
             "require": {
@@ -744,7 +1674,7 @@
                 "ext-json": "*",
                 "ext-tokenizer": "*",
                 "php": "^5.6 || >=7.0 <7.3",
-                "php-cs-fixer/diff": "^1.2",
+                "php-cs-fixer/diff": "^1.3",
                 "symfony/console": "^3.2 || ^4.0",
                 "symfony/event-dispatcher": "^3.0 || ^4.0",
                 "symfony/filesystem": "^3.0 || ^4.0",
@@ -765,7 +1695,7 @@
                 "mikey179/vfsstream": "^1.6",
                 "php-coveralls/php-coveralls": "^2.0",
                 "php-cs-fixer/accessible-object": "^1.0",
-                "phpunit/phpunit": "^5.7.23 || ^6.4.3",
+                "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0",
                 "phpunitgoodpractices/traits": "^1.3.1",
                 "symfony/phpunit-bridge": "^3.2.2 || ^4.0"
             },
@@ -777,6 +1707,11 @@
                 "php-cs-fixer"
             ],
             "type": "application",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.11-dev"
+                }
+            },
             "autoload": {
                 "psr-4": {
                     "PhpCsFixer\\": "src/"
@@ -787,6 +1722,8 @@
                     "tests/Test/AbstractIntegrationTestCase.php",
                     "tests/Test/Assert/AssertTokensTrait.php",
                     "tests/Test/Constraint/SameStringsConstraint.php",
+                    "tests/Test/Constraint/SameStringsConstraintForV5.php",
+                    "tests/Test/Constraint/SameStringsConstraintForV7.php",
                     "tests/Test/IntegrationCase.php",
                     "tests/Test/IntegrationCaseFactory.php",
                     "tests/Test/IntegrationCaseFactoryInterface.php",
@@ -809,7 +1746,7 @@
                 }
             ],
             "description": "A tool to automatically fix PHP code style",
-            "time": "2018-03-08T11:13:12+00:00"
+            "time": "2018-03-21T17:41:26+00:00"
         },
         {
             "name": "myclabs/deep-copy",
@@ -858,16 +1795,16 @@
         },
         {
             "name": "paragonie/random_compat",
-            "version": "v2.0.11",
+            "version": "v2.0.12",
             "source": {
                 "type": "git",
                 "url": "https://github.com/paragonie/random_compat.git",
-                "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8"
+                "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/5da4d3c796c275c55f057af5a643ae297d96b4d8",
-                "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8",
+                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb",
+                "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb",
                 "shasum": ""
             },
             "require": {
@@ -902,7 +1839,7 @@
                 "pseudorandom",
                 "random"
             ],
-            "time": "2017-09-27T21:40:39+00:00"
+            "time": "2018-04-04T21:24:14+00:00"
         },
         {
             "name": "php-cs-fixer/diff",
@@ -1103,23 +2040,23 @@
         },
         {
             "name": "phpspec/prophecy",
-            "version": "1.7.5",
+            "version": "1.7.6",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpspec/prophecy.git",
-                "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401"
+                "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/dfd6be44111a7c41c2e884a336cc4f461b3b2401",
-                "reference": "dfd6be44111a7c41c2e884a336cc4f461b3b2401",
+                "url": "https://api.github.com/repos/phpspec/prophecy/zipball/33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
+                "reference": "33a7e3c4fda54e912ff6338c48823bd5c0f0b712",
                 "shasum": ""
             },
             "require": {
                 "doctrine/instantiator": "^1.0.2",
                 "php": "^5.3|^7.0",
                 "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
-                "sebastian/comparator": "^1.1|^2.0",
+                "sebastian/comparator": "^1.1|^2.0|^3.0",
                 "sebastian/recursion-context": "^1.0|^2.0|^3.0"
             },
             "require-dev": {
@@ -1162,7 +2099,7 @@
                 "spy",
                 "stub"
             ],
-            "time": "2018-02-19T10:16:54+00:00"
+            "time": "2018-04-18T13:57:24+00:00"
         },
         {
             "name": "phpunit/php-code-coverage",
@@ -1521,85 +2458,38 @@
             "require-dev": {
                 "phpunit/phpunit": "^5.4"
             },
-            "suggest": {
-                "ext-soap": "*"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.2.x-dev"
-                }
-            },
-            "autoload": {
-                "classmap": [
-                    "src/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "BSD-3-Clause"
-            ],
-            "authors": [
-                {
-                    "name": "Sebastian Bergmann",
-                    "email": "sb@sebastian-bergmann.de",
-                    "role": "lead"
-                }
-            ],
-            "description": "Mock Object library for PHPUnit",
-            "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
-            "keywords": [
-                "mock",
-                "xunit"
-            ],
-            "time": "2017-06-30T09:13:00+00:00"
-        },
-        {
-            "name": "psr/log",
-            "version": "1.0.2",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/php-fig/log.git",
-                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
-                "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.0"
-            },
+            "suggest": {
+                "ext-soap": "*"
+            },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.0.x-dev"
+                    "dev-master": "3.2.x-dev"
                 }
             },
             "autoload": {
-                "psr-4": {
-                    "Psr\\Log\\": "Psr/Log/"
-                }
+                "classmap": [
+                    "src/"
+                ]
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
-                "MIT"
+                "BSD-3-Clause"
             ],
             "authors": [
                 {
-                    "name": "PHP-FIG",
-                    "homepage": "http://www.php-fig.org/"
+                    "name": "Sebastian Bergmann",
+                    "email": "sb@sebastian-bergmann.de",
+                    "role": "lead"
                 }
             ],
-            "description": "Common interface for logging libraries",
-            "homepage": "https://github.com/php-fig/log",
+            "description": "Mock Object library for PHPUnit",
+            "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/",
             "keywords": [
-                "log",
-                "psr",
-                "psr-3"
+                "mock",
+                "xunit"
             ],
-            "time": "2016-10-10T12:19:37+00:00"
+            "time": "2017-06-30T09:13:00+00:00"
         },
         {
             "name": "sebastian/code-unit-reverse-lookup",
@@ -2114,143 +3004,18 @@
             "homepage": "https://github.com/sebastianbergmann/version",
             "time": "2016-10-03T07:35:21+00:00"
         },
-        {
-            "name": "symfony/console",
-            "version": "v3.4.6",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/console.git",
-                "reference": "067339e9b8ec30d5f19f5950208893ff026b94f7"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/console/zipball/067339e9b8ec30d5f19f5950208893ff026b94f7",
-                "reference": "067339e9b8ec30d5f19f5950208893ff026b94f7",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5.9|>=7.0.8",
-                "symfony/debug": "~2.8|~3.0|~4.0",
-                "symfony/polyfill-mbstring": "~1.0"
-            },
-            "conflict": {
-                "symfony/dependency-injection": "<3.4",
-                "symfony/process": "<3.3"
-            },
-            "require-dev": {
-                "psr/log": "~1.0",
-                "symfony/config": "~3.3|~4.0",
-                "symfony/dependency-injection": "~3.4|~4.0",
-                "symfony/event-dispatcher": "~2.8|~3.0|~4.0",
-                "symfony/lock": "~3.4|~4.0",
-                "symfony/process": "~3.3|~4.0"
-            },
-            "suggest": {
-                "psr/log": "For using the console logger",
-                "symfony/event-dispatcher": "",
-                "symfony/lock": "",
-                "symfony/process": ""
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Console\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Console Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-02-26T15:46:28+00:00"
-        },
-        {
-            "name": "symfony/debug",
-            "version": "v3.4.6",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/debug.git",
-                "reference": "9b1071f86e79e1999b3d3675d2e0e7684268b9bc"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/debug/zipball/9b1071f86e79e1999b3d3675d2e0e7684268b9bc",
-                "reference": "9b1071f86e79e1999b3d3675d2e0e7684268b9bc",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5.9|>=7.0.8",
-                "psr/log": "~1.0"
-            },
-            "conflict": {
-                "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2"
-            },
-            "require-dev": {
-                "symfony/http-kernel": "~2.8|~3.0|~4.0"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Debug\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Debug Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-02-28T21:49:22+00:00"
-        },
         {
             "name": "symfony/event-dispatcher",
-            "version": "v3.4.6",
+            "version": "v3.4.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/event-dispatcher.git",
-                "reference": "58990682ac3fdc1f563b7e705452921372aad11d"
+                "reference": "fdd5abcebd1061ec647089c6c41a07ed60af09f8"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/58990682ac3fdc1f563b7e705452921372aad11d",
-                "reference": "58990682ac3fdc1f563b7e705452921372aad11d",
+                "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/fdd5abcebd1061ec647089c6c41a07ed60af09f8",
+                "reference": "fdd5abcebd1061ec647089c6c41a07ed60af09f8",
                 "shasum": ""
             },
             "require": {
@@ -2300,11 +3065,11 @@
             ],
             "description": "Symfony EventDispatcher Component",
             "homepage": "https://symfony.com",
-            "time": "2018-02-14T10:03:57+00:00"
+            "time": "2018-04-06T07:35:25+00:00"
         },
         {
             "name": "symfony/filesystem",
-            "version": "v3.4.6",
+            "version": "v3.4.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/filesystem.git",
@@ -2353,16 +3118,16 @@
         },
         {
             "name": "symfony/finder",
-            "version": "v3.4.6",
+            "version": "v3.4.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/finder.git",
-                "reference": "a479817ce0a9e4adfd7d39c6407c95d97c254625"
+                "reference": "bd14efe8b1fabc4de82bf50dce62f05f9a102433"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/finder/zipball/a479817ce0a9e4adfd7d39c6407c95d97c254625",
-                "reference": "a479817ce0a9e4adfd7d39c6407c95d97c254625",
+                "url": "https://api.github.com/repos/symfony/finder/zipball/bd14efe8b1fabc4de82bf50dce62f05f9a102433",
+                "reference": "bd14efe8b1fabc4de82bf50dce62f05f9a102433",
                 "shasum": ""
             },
             "require": {
@@ -2398,11 +3163,11 @@
             ],
             "description": "Symfony Finder Component",
             "homepage": "https://symfony.com",
-            "time": "2018-03-05T18:28:11+00:00"
+            "time": "2018-04-04T05:07:11+00:00"
         },
         {
             "name": "symfony/options-resolver",
-            "version": "v3.4.6",
+            "version": "v3.4.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/options-resolver.git",
@@ -2454,65 +3219,6 @@
             ],
             "time": "2018-01-11T07:56:07+00:00"
         },
-        {
-            "name": "symfony/polyfill-mbstring",
-            "version": "v1.7.0",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/78be803ce01e55d3491c1397cf1c64beb9c1b63b",
-                "reference": "78be803ce01e55d3491c1397cf1c64beb9c1b63b",
-                "shasum": ""
-            },
-            "require": {
-                "php": ">=5.3.3"
-            },
-            "suggest": {
-                "ext-mbstring": "For best performance"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "1.7-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Polyfill\\Mbstring\\": ""
-                },
-                "files": [
-                    "bootstrap.php"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Nicolas Grekas",
-                    "email": "p@tchwork.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony polyfill for the Mbstring extension",
-            "homepage": "https://symfony.com",
-            "keywords": [
-                "compatibility",
-                "mbstring",
-                "polyfill",
-                "portable",
-                "shim"
-            ],
-            "time": "2018-01-30T19:27:44+00:00"
-        },
         {
             "name": "symfony/polyfill-php70",
             "version": "v1.7.0",
@@ -2629,16 +3335,16 @@
         },
         {
             "name": "symfony/process",
-            "version": "v3.4.6",
+            "version": "v3.4.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/process.git",
-                "reference": "cc4aea21f619116aaf1c58016a944e4821c8e8af"
+                "reference": "4b7d64e852886319e93ddfdecff0d744ab87658b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/process/zipball/cc4aea21f619116aaf1c58016a944e4821c8e8af",
-                "reference": "cc4aea21f619116aaf1c58016a944e4821c8e8af",
+                "url": "https://api.github.com/repos/symfony/process/zipball/4b7d64e852886319e93ddfdecff0d744ab87658b",
+                "reference": "4b7d64e852886319e93ddfdecff0d744ab87658b",
                 "shasum": ""
             },
             "require": {
@@ -2674,11 +3380,11 @@
             ],
             "description": "Symfony Process Component",
             "homepage": "https://symfony.com",
-            "time": "2018-02-12T17:55:00+00:00"
+            "time": "2018-04-03T05:22:50+00:00"
         },
         {
             "name": "symfony/stopwatch",
-            "version": "v3.4.6",
+            "version": "v3.4.8",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/stopwatch.git",
@@ -2725,64 +3431,6 @@
             "homepage": "https://symfony.com",
             "time": "2018-02-17T14:55:25+00:00"
         },
-        {
-            "name": "symfony/yaml",
-            "version": "v3.4.6",
-            "source": {
-                "type": "git",
-                "url": "https://github.com/symfony/yaml.git",
-                "reference": "6af42631dcf89e9c616242c900d6c52bd53bd1bb"
-            },
-            "dist": {
-                "type": "zip",
-                "url": "https://api.github.com/repos/symfony/yaml/zipball/6af42631dcf89e9c616242c900d6c52bd53bd1bb",
-                "reference": "6af42631dcf89e9c616242c900d6c52bd53bd1bb",
-                "shasum": ""
-            },
-            "require": {
-                "php": "^5.5.9|>=7.0.8"
-            },
-            "conflict": {
-                "symfony/console": "<3.4"
-            },
-            "require-dev": {
-                "symfony/console": "~3.4|~4.0"
-            },
-            "suggest": {
-                "symfony/console": "For validating YAML files using the lint command"
-            },
-            "type": "library",
-            "extra": {
-                "branch-alias": {
-                    "dev-master": "3.4-dev"
-                }
-            },
-            "autoload": {
-                "psr-4": {
-                    "Symfony\\Component\\Yaml\\": ""
-                },
-                "exclude-from-classmap": [
-                    "/Tests/"
-                ]
-            },
-            "notification-url": "https://packagist.org/downloads/",
-            "license": [
-                "MIT"
-            ],
-            "authors": [
-                {
-                    "name": "Fabien Potencier",
-                    "email": "fabien@symfony.com"
-                },
-                {
-                    "name": "Symfony Community",
-                    "homepage": "https://symfony.com/contributors"
-                }
-            ],
-            "description": "Symfony Yaml Component",
-            "homepage": "https://symfony.com",
-            "time": "2018-02-16T09:50:28+00:00"
-        },
         {
             "name": "webmozart/assert",
             "version": "1.3.0",
diff --git a/locale/en.json b/locale/en.json
index 206b5928d8e3e198d43389394352cbd8eeb32cfc..b25832f2d8762ae59a30f88c1a984697af469c69 100644
--- a/locale/en.json
+++ b/locale/en.json
@@ -36,6 +36,9 @@
       "Expiration date": "Expiry date",
       "Fail": "Fail",
       "Failed:": "Failed:",
+      "Status": "Status",
+      "Waiting": "Waiting",
+      "Executed": "Executed",
       "Format": "Format",
       "Installation": "Installation",
       "Logs": "Logs",
@@ -237,8 +240,11 @@
       "AppName": "Application name",
       "CleanUrl": "Clean URL",
       "Database": "Database name",
-      "DbConnectionString": "Connection string",
+      "DbDriver": "Database driver",
+      "DbHost": "Database hostname",
+      "DbName": "Database name",
       "DbPassword": "Password",
+      "DbPort": "Database port",
       "DbPrefix": "Prefix",
       "DbUser": "User",
       "DefaultLanguage": "Default language",
diff --git a/locale/fr.json b/locale/fr.json
index f63beb9273101101ee20601135a41ce851bdad3e..04a01b96d8d6716e58079f9932cc7a474e1d0a56 100644
--- a/locale/fr.json
+++ b/locale/fr.json
@@ -54,6 +54,9 @@
       "Summary": "Résumé",
       "Title": "Titre",
       "Votes": "Votes",
+      "Status": "Statut",
+      "Waiting": "En attente",
+      "Executed": "Exécutées",
       "polls in the database at this time": "sondages dans la base actuellement"
    },
    "Check": {
@@ -237,8 +240,11 @@
       "AppName": "Nom de l'application",
       "CleanUrl": "URL propres",
       "Database": "Base de données",
-      "DbConnectionString": "Chaîne de connexion",
+      "DbDriver": "Pilote de la base de données",
+      "DbHost": "Nom d'hôte",
+      "DbName": "Nom de la base de données",
       "DbPassword": "Mot de passe",
+      "DbPort": "Port du serveur",
       "DbPrefix": "Préfixe",
       "DbUser": "Utilisateur·rice",
       "DefaultLanguage": "Langue par défaut",
diff --git a/locale/fr_FR.json b/locale/fr_FR.json
index f63beb9273101101ee20601135a41ce851bdad3e..04a01b96d8d6716e58079f9932cc7a474e1d0a56 100644
--- a/locale/fr_FR.json
+++ b/locale/fr_FR.json
@@ -54,6 +54,9 @@
       "Summary": "Résumé",
       "Title": "Titre",
       "Votes": "Votes",
+      "Status": "Statut",
+      "Waiting": "En attente",
+      "Executed": "Exécutées",
       "polls in the database at this time": "sondages dans la base actuellement"
    },
    "Check": {
@@ -237,8 +240,11 @@
       "AppName": "Nom de l'application",
       "CleanUrl": "URL propres",
       "Database": "Base de données",
-      "DbConnectionString": "Chaîne de connexion",
+      "DbDriver": "Pilote de la base de données",
+      "DbHost": "Nom d'hôte",
+      "DbName": "Nom de la base de données",
       "DbPassword": "Mot de passe",
+      "DbPort": "Port du serveur",
       "DbPrefix": "Préfixe",
       "DbUser": "Utilisateur·rice",
       "DefaultLanguage": "Langue par défaut",
diff --git a/tpl/admin/config.tpl b/tpl/admin/config.tpl
index 765131bab65a82380688e79c502b9a93562d6a4f..aade5072aa11b949fbd264cc9d5e1e299963d13a 100644
--- a/tpl/admin/config.tpl
+++ b/tpl/admin/config.tpl
@@ -31,11 +31,20 @@ const ADRESSEMAILADMIN = '{$appMail}';
 // Email for automatic responses (you should set it to "no-reply")
 const ADRESSEMAILREPONSEAUTO = '{$responseMail}';
 
-// Database server name, leave empty to use a socket
-const DB_CONNECTION_STRING = '{$dbConnectionString}';
+// Database driver
+const DB_DRIVER = '{$dbDriver}';
+
+// Database name
+const DB_NAME = '{$dbName}';
+
+// Database host
+const DB_HOST = '{$dbHost}';
+
+// Database port
+const DB_PORT = '{$dbPort}';
 
 // Database user
-const DB_USER= '{$dbUser}';
+const DB_USER = '{$dbUser}';
 
 // Database password
 const DB_PASSWORD = '{$dbPassword|addslashes_single_quote}';
diff --git a/tpl/admin/install.tpl b/tpl/admin/install.tpl
index 38f613cc5bcaaffcbc3db3cd95c8b32960e4a5b1..d585bce60b8c16a6764bda342def9b53d9d8bbd1 100644
--- a/tpl/admin/install.tpl
+++ b/tpl/admin/install.tpl
@@ -17,38 +17,53 @@
                             <label for="appName" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'AppName')}</label>
                             <input type="text" class="form-control" id="appName" name="appName" value="{$fields['appName']}" autofocus required>
                         </div>
+                        <p class="help-block">Le nom de l'application qui sera notamment utilisé dans les emails.</p>
                     </div>
 
-                    <div class="form-group">
-                        <div class="input-group">
-                            <label for="appMail" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'AppMail')}</label>
-                            <input type="email" class="form-control" id="appMail" name="appMail" value="{$fields['appMail']}" required>
+                    <div class="row">
+                        <div class="col-md-6">
+                            <div class="form-group">
+                                <div class="input-group">
+                                    <label for="appMail" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'AppMail')}</label>
+                                    <input type="email" class="form-control" id="appMail" name="appMail" value="{$fields['appMail']}" required>
+                                </div>
+                                <p class="help-block">L'adresse email de l'administrateur qui sera fournie en cas de souci.</p>
+                            </div>
                         </div>
-                    </div>
-
-                    <div class="form-group">
-                        <div class="input-group">
-                            <label for="responseMail" class="input-group-addon">{__('Installation', 'ResponseMail')}</label>
-                            <input type="email" class="form-control" id="responseMail" name="responseMail" value="{$fields['responseMail']}">
+                        <div class="col-md-6">
+                            <div class="form-group">
+                                <div class="input-group">
+                                    <label for="responseMail" class="input-group-addon">{__('Installation', 'ResponseMail')}</label>
+                                    <input type="email" class="form-control" id="responseMail" name="responseMail" value="{$fields['responseMail']}">
+                                </div>
+                                <p class="help-block">L'adresse de réponse des couriels envoyés par l'application.</p>
+                            </div>
                         </div>
                     </div>
 
-                    <div class="form-group">
-                        <div class="input-group">
-                            <label for="defaultLanguage" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'DefaultLanguage')}</label>
-                            <select type="email" class="form-control" id="defaultLanguage" name="defaultLanguage" required>
-                                {foreach $langs as $lang=>$label}
-                                    <option value="{$lang}" {if $lang==$fields['defaultLanguage']}selected{/if}>{$label}</option>
-                                {/foreach}
-                            </select>
+                    <div class="row">
+                        <div class="col-md-6">
+                            <div class="form-group">
+                                <div class="input-group">
+                                    <label for="defaultLanguage" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'DefaultLanguage')}</label>
+                                    <select type="email" class="form-control" id="defaultLanguage" name="defaultLanguage" required>
+                                        {foreach $langs as $lang=>$label}
+                                            <option value="{$lang}" {if $lang==$fields['defaultLanguage']}selected{/if}>{$label}</option>
+                                        {/foreach}
+                                    </select>
+                                </div>
+                            </div>
                         </div>
-                    </div>
+                        <div class="col-md-6">
 
-                    <div class="input-group">
-                        <label for="cleanUrl" class="input-group-addon">{__('Installation', 'CleanUrl')}</label>
+                            <div class="input-group">
+                                <label for="cleanUrl" class="input-group-addon">{__('Installation', 'CleanUrl')}</label>
 
-                        <div class="form-control">
-                            <input type="checkbox" id="cleanUrl" name="cleanUrl" {($fields['cleanUrl']) ? 'checked' : ''}>
+                                <div class="form-control">
+                                    <input type="checkbox" id="cleanUrl" name="cleanUrl" {($fields['cleanUrl']) ? 'checked' : ''}>
+                                    <p class="help-block">Utiliser la réécriture d'URL pour obtenir de belles URLs.</p>
+                                </div>
+                            </div>
                         </div>
                     </div>
                 </div>
@@ -56,38 +71,91 @@
 
             <fieldset>
                 <legend>{__('Installation', 'Database')}</legend>
+
                 <div class="form-group">
-                    <div class="input-group">
-                        <label for="dbConnectionString" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'DbConnectionString')}</label>
-                        <input type="text" class="form-control" id="dbConnectionString" name="dbConnectionString" value="{$fields['dbConnectionString']}" required>
+                    {__('Installation', 'DbDriver')}
+                    <div class="radio">
+                        <label>
+                            <input type="radio" name="dbDriver" id="dbDriver_mysql" value="pdo_mysql" checked>
+                            MySQL
+                        </label>
+                    </div>
+                    <div class="radio">
+                        <label>
+                            <input type="radio" name="dbDriver" id="dbDriver_pgsql" value="pdo_pgsql">
+                            PostgreSQL
+                        </label>
                     </div>
                 </div>
 
-                <div class="form-group">
-                    <div class="input-group">
-                        <label for="dbUser" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'DbUser')}</label>
-                        <input type="text" class="form-control" id="dbUser" name="dbUser" value="{$fields['dbUser']}" required>
+                <div class="row">
+                    <div class="col-md-8">
+                        <div class="form-group">
+                            <div class="input-group">
+                                <label for="dbHost" class="input-group-addon">{__('Installation', 'DbHost')}</label>
+                                <input type="text" class="form-control" id="dbHost" name="dbHost" value="{$fields['dbHost']}" required>
+                            </div>
+                            <p class="help-block">Le nom d'hôte du serveur de base de données, <code>localhost</code> si le serveur est le même.</p>
+                        </div>
+                    </div>
+
+                    <div class="col-md-4">
+                        <div class="form-group">
+                            <div class="input-group">
+                                <label for="dbPort" class="input-group-addon">{__('Installation', 'DbPort')}</label>
+                                <input type="text" class="form-control" id="dbPort" name="dbPort" value="{$fields['dbPort']}">
+                            </div>
+                            <p class="help-block">Port 3306 par défaut pour MySQL, 5432 pour PostgreSQL</p>
+                        </div>
                     </div>
                 </div>
 
                 <div class="form-group">
                     <div class="input-group">
-                        <label for="dbPassword" class="input-group-addon">{__('Installation', 'DbPassword')}</label>
-                        <input type="password" class="form-control" id="dbPassword" name="dbPassword" value="{$fields['dbPassword']}">
+                        <label for="dbName" class="input-group-addon">{__('Installation', 'DbName')}</label>
+                        <input type="text" class="form-control" id="dbName" name="dbName" value="{$fields['dbName']}">
                     </div>
                 </div>
 
-                <div class="form-group">
-                    <div class="input-group">
-                        <label for="dbPrefix" class="input-group-addon">{__('Installation', 'DbPrefix')}</label>
-                        <input type="text" class="form-control" id="dbPrefix" name="dbPrefix" value="{$fields['dbPrefix']}">
+                <div class="row">
+                    <div class="col-md-6">
+                        <div class="form-group">
+                            <div class="input-group">
+                                <label for="dbUser" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'DbUser')}</label>
+                                <input type="text" class="form-control" id="dbUser" name="dbUser" value="{$fields['dbUser']}" required>
+                            </div>
+                        </div>
+                    </div>
+
+                    <div class="col-md-6">
+                        <div class="form-group">
+                            <div class="input-group">
+                                <label for="dbPassword" class="input-group-addon">{__('Installation', 'DbPassword')}</label>
+                                <input type="password" class="form-control" id="dbPassword" name="dbPassword" value="{$fields['dbPassword']}">
+                            </div>
+                        </div>
                     </div>
                 </div>
 
-                <div class="form-group">
-                    <div class="input-group">
-                        <label for="migrationTable" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'MigrationTable')}</label>
-                        <input type="text" class="form-control" id="migrationTable" name="migrationTable" value="{$fields['migrationTable']}" required>
+                <div class="row">
+                    <div class="col-md-6">
+                        <div class="form-group">
+                            <div class="input-group">
+                                <label for="dbPrefix" class="input-group-addon">{__('Installation', 'DbPrefix')}</label>
+                                <input type="text" class="form-control" id="dbPrefix" name="dbPrefix" value="{$fields['dbPrefix']}">
+                            </div>
+                            <p class="help-block">Le préfixe à appliquer devant les tables</p>
+                        </div>
+                    </div>
+
+                    <div class="col-md-6">
+                        <div class="form-group">
+                            <div class="input-group">
+                                <label for="migrationTable" class="input-group-addon">{__('Generic', 'ASTERISK')} {__('Installation', 'MigrationTable')}</label>
+                                <input type="text" class="form-control" id="migrationTable" name="migrationTable" value="{$fields['migrationTable']}" required>
+                            </div>
+                            <p class="help-block">La table utilisée pour stocker les migrations</p>
+                        </div>
                     </div>
                 </div>
             </fieldset>
diff --git a/tpl/admin/migration.tpl b/tpl/admin/migration.tpl
index b508264e7337757e52de910db8cf3a99df8eea99..89306258c912cd9db6427cdbc53d3fb1439f7c4e 100644
--- a/tpl/admin/migration.tpl
+++ b/tpl/admin/migration.tpl
@@ -1,39 +1,36 @@
 {extends 'admin/admin_page.tpl'}
 
 {block 'admin_main'}
+    {if $executing}
+        <div class="row">
+            <pre>{$output}</pre>
+            <div class="col-xs-12 well well-sm">
+                {__('Generic', 'Page generated in')} {$time} {__('Generic', 'seconds')}
+            </div>
+        </div>
+    {/if}
     <div class="row">
         <div class="col-xs-12 col-md-4">
-            <h2>{__('Admin', 'Summary')}</h2>
-            {__('Admin', 'Succeeded:')} <span class="label label-warning">{$countSucceeded|html} / {$countTotal|html}</span>
-            <br/>
-            {__('Admin', 'Failed:')} <span class="label label-danger">{$countFailed|html} / {$countTotal|html}</span>
-            <br/>
-            {__('Admin', 'Skipped:')} <span class="label label-info">{$countSkipped|html} / {$countTotal|html}</span>
+            <h2>{__('Admin', 'Status')}</h2>
+            {if $countExecuted === $countTotal}
+                <div class="alert alert-success">
+                    No migrations to execute
+                </div>
+            {else}
+                <div class="alert alert-danger">
+                    <form method="POST">
+                        <button type="submit" class="btn btn-danger btn-lg" name="execute">Execute migration</button>
+                    </form>
+                    <br />
+                    {$countWaiting|html} migrations available.
+                </div>
+            {/if}
         </div>
         <div class="col-xs-12 col-md-4">
-            <h2>{__('Admin', 'Success')}</h2>
-            <ul>
-                {foreach $success as $s}
-                    <li>{$s|html}</li>
-                    {foreachelse}
-                    <li>{__('Admin', 'Nothing')}</li>
-                {/foreach}
-            </ul>
-        </div>
-
-        <div class="col-xs-12 col-md-4">
-            <h2>{__('Admin', 'Fail')}</h2>
-            <ul>
-                {foreach $fail as $f}
-                    <li>{$f|html}</li>
-                    {foreachelse}
-                    <li>{__('Admin', 'Nothing')}</li>
-                {/foreach}
-            </ul>
-        </div>
-
-        <div class="col-xs-12 well well-sm">
-            {__('Generic', 'Page generated in')} {$time} {__('Generic', 'seconds')}
+            <h2>{__('Admin', 'Summary')}</h2>
+            {__('Admin', 'Waiting')} <span class="label label-warning">{$countWaiting|html} / {$countTotal|html}</span>
+            <br/>
+            {__('Admin', 'Executed')} <span class="label label-success">{$countExecuted|html} / {$countTotal|html}</span>
         </div>
     </div>
 {/block}
diff --git a/tpl/part/vote_table_classic.tpl b/tpl/part/vote_table_classic.tpl
index aed5b9124e82546a8442251337b6c4bd01021cc3..aeda5fc0f6396141320c063d9cc29fe76708bbf1 100644
--- a/tpl/part/vote_table_classic.tpl
+++ b/tpl/part/vote_table_classic.tpl
@@ -199,7 +199,7 @@
                     {foreach $slots as $id=>$slot}
                         <td class="bg-info" headers="C{$id}">
                             <ul class="list-unstyled choice">
-								{if $poll->ValueMax eq NULL || $best_choices['y'][$i] lt $poll->ValueMax}
+								{if $poll->valuemax eq NULL || $best_choices['y'][$i] lt $poll->valuemax}
                                	 	<li class="yes">
                                     	<input type="radio" id="y-choice-{$id}" name="choices[{$id}]" value="2"
                                     		{(!isset($selectedNewVotes[$id]) || ("2" !== $selectedNewVotes[$id])) ? "" : " checked"}
diff --git a/tpl/part/vote_table_date.tpl b/tpl/part/vote_table_date.tpl
index f38ae724812fd4ee0783ec02e9e6fc1ebf406021..ae06a39ac707fb8c88e4f094156360e042621281 100644
--- a/tpl/part/vote_table_date.tpl
+++ b/tpl/part/vote_table_date.tpl
@@ -258,7 +258,7 @@
 
                             <td class="bg-info" headers="M{$headersM[$i]} D{$headersD[$i]} H{$headersH[$i]}">
                                 <ul class="list-unstyled choice">
-                                    {if $poll->ValueMax eq NULL || $best_choices['y'][$i] lt $poll->ValueMax}
+                                    {if $poll->valuemax eq NULL || $best_choices['y'][$i] lt $poll->valuemax}
                                     <li class="yes">
                                         <input type="radio" id="y-choice-{$i}" name="choices[{$i}]" value="2"
                                         	{(!isset($selectedNewVotes[$i]) || ("2" !== $selectedNewVotes[$i])) ? "" : " checked"}
diff --git a/tpl/studs.tpl b/tpl/studs.tpl
index 202fbac27f6328c7d48d48f711d58ccead5c1cb4..d4a1017d69ef4adda2262377c3bac4a4e60351ae 100644
--- a/tpl/studs.tpl
+++ b/tpl/studs.tpl
@@ -17,7 +17,6 @@
 
 {block name=main}
 
-
     {* Messages *}
     {include 'part/messages.tpl'}