From 006a1915449dc92b29de741c56a775ede9333e01 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Wed, 18 Apr 2018 16:16:22 +0200 Subject: [PATCH] Make Framadate compatible with PostgreSQL and great again ! * Move the database handling to Doctrine DBAL * Move Migrations to Doctrine Migrations * Rename migrations for Doctrine Migrations Uses * Fix Migrations * Change config parameters, introduce db name, host and port parameters and get rid of database url * Change install form for this * Add a CLI command to make migrations * Add config.test.php to be used with APP_ENV=test for testing Signed-off-by: Thomas Citharel CS Signed-off-by: Thomas Citharel Add sqlite to CI and execute migration in test env Signed-off-by: Thomas Citharel Typo Signed-off-by: Thomas Citharel SQLite is already inside the image... Signed-off-by: Thomas Citharel Rebase two new migrations Signed-off-by: Thomas Citharel Move from trait to abstract class and remove legacy migration table after checks Signed-off-by: Thomas Citharel CS Signed-off-by: Thomas Citharel Move doctrine command path inside CI Signed-off-by: Thomas Citharel Move abstract migration class to correct namespace and remove unused command Signed-off-by: Thomas Citharel CS Signed-off-by: Thomas Citharel Check for legacy migration table existence Signed-off-by: Thomas Citharel Check if legacy migration table exists before deleting it Signed-off-by: Thomas Citharel Add messages for skipped migrations and fix an issue with MySQL ERR_NO_DATE Migration Signed-off-by: Thomas Citharel --- .gitignore | 1 + .gitlab-ci.yml | 1 + admin/migration.php | 144 +- app/classes/Framadate/AbstractMigration.php | 54 + app/classes/Framadate/FramaDB.php | 22 +- .../AddColumn_hidden_In_poll_For_0_9.php | 75 - .../AddColumn_receiveNewComments_For_0_9.php | 76 - .../AddColumn_uniqId_In_vote_For_0_9.php | 77 - ...sults_publicly_visible_In_poll_For_0_9.php | 76 - .../Migration/Fix_MySQL_No_Zero_Date.php | 70 - .../Migration/From_0_0_to_0_8_Migration.php | 108 -- .../Migration/From_0_8_to_0_9_Migration.php | 292 ---- .../Generate_uniqId_for_old_votes.php | 80 - .../Migration/Increase_pollId_size.php | 66 - .../Migration/RPadVotes_from_0_8.php | 66 - .../Migrations/Version20150101000000.php | 99 ++ .../Migrations/Version20150102000000.php | 160 ++ .../Migrations/Version20150102100000.php | 263 +++ .../Migrations/Version20150117000000.php | 70 + .../Migrations/Version20150402000000.php | 76 + .../Migrations/Version20150405000000.php | 72 + .../Migrations/Version20150624000000.php | 78 + .../Migrations/Version20150918000000.php | 102 ++ .../Version20151012075900.php} | 53 +- .../Version20151012082600.php} | 51 +- .../Migrations/Version20151028000000.php | 72 + .../Migrations/Version20151205000000.php | 51 + .../Version20180220000000.php} | 49 +- .../Migrations/Version20180411000000.php | 88 + .../Version20180419170000.php} | 53 +- .../Version20180419180000.php} | 53 +- .../Version20180419190000.php} | 44 +- .../Repositories/AbstractRepository.php | 48 +- .../Repositories/CommentRepository.php | 56 +- .../Framadate/Repositories/PollRepository.php | 147 +- .../Repositories/RepositoryFactory.php | 6 +- .../Framadate/Repositories/SlotRepository.php | 68 +- .../Framadate/Repositories/VoteRepository.php | 91 +- .../Framadate/Services/AdminPollService.php | 10 +- .../Framadate/Services/InstallService.php | 36 +- .../Framadate/Services/PollService.php | 20 +- .../Framadate/Services/PurgeService.php | 65 +- app/classes/Framadate/Utils.php | 7 +- app/inc/config.test.php | 116 ++ app/inc/init.php | 40 +- app/inc/smarty.php | 5 +- .../Services/InputServiceUnitTest.php | 37 +- bin/doctrine | 58 + composer.json | 5 +- composer.lock | 1480 ++++++++++++----- locale/en.json | 8 +- locale/fr.json | 8 +- locale/fr_FR.json | 8 +- tpl/admin/config.tpl | 15 +- tpl/admin/install.tpl | 152 +- tpl/admin/migration.tpl | 55 +- tpl/part/vote_table_classic.tpl | 2 +- tpl/part/vote_table_date.tpl | 2 +- tpl/studs.tpl | 1 - 59 files changed, 3238 insertions(+), 1950 deletions(-) create mode 100644 app/classes/Framadate/AbstractMigration.php delete mode 100644 app/classes/Framadate/Migration/AddColumn_hidden_In_poll_For_0_9.php delete mode 100644 app/classes/Framadate/Migration/AddColumn_receiveNewComments_For_0_9.php delete mode 100644 app/classes/Framadate/Migration/AddColumn_uniqId_In_vote_For_0_9.php delete mode 100644 app/classes/Framadate/Migration/AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9.php delete mode 100644 app/classes/Framadate/Migration/Fix_MySQL_No_Zero_Date.php delete mode 100644 app/classes/Framadate/Migration/From_0_0_to_0_8_Migration.php delete mode 100644 app/classes/Framadate/Migration/From_0_8_to_0_9_Migration.php delete mode 100644 app/classes/Framadate/Migration/Generate_uniqId_for_old_votes.php delete mode 100644 app/classes/Framadate/Migration/Increase_pollId_size.php delete mode 100644 app/classes/Framadate/Migration/RPadVotes_from_0_8.php create mode 100644 app/classes/Framadate/Migrations/Version20150101000000.php create mode 100644 app/classes/Framadate/Migrations/Version20150102000000.php create mode 100644 app/classes/Framadate/Migrations/Version20150102100000.php create mode 100644 app/classes/Framadate/Migrations/Version20150117000000.php create mode 100644 app/classes/Framadate/Migrations/Version20150402000000.php create mode 100644 app/classes/Framadate/Migrations/Version20150405000000.php create mode 100644 app/classes/Framadate/Migrations/Version20150624000000.php create mode 100644 app/classes/Framadate/Migrations/Version20150918000000.php rename app/classes/Framadate/{Migration/Alter_Comment_table_for_name_length.php => Migrations/Version20151012075900.php} (50%) rename app/classes/Framadate/{Migration/Alter_Comment_table_adding_date.php => Migrations/Version20151012082600.php} (53%) create mode 100644 app/classes/Framadate/Migrations/Version20151028000000.php create mode 100644 app/classes/Framadate/Migrations/Version20151205000000.php rename app/classes/Framadate/{Migration/AddColumn_ValueMax_In_poll_For_1_1.php => Migrations/Version20180220000000.php} (55%) create mode 100644 app/classes/Framadate/Migrations/Version20180411000000.php rename app/classes/Framadate/{Migration/AddColumn_collect_mail_In_poll.php => Migrations/Version20180419170000.php} (52%) rename app/classes/Framadate/{Migration/AddColumn_mail_In_vote.php => Migrations/Version20180419180000.php} (52%) rename app/classes/Framadate/{Migration/Migration.php => Migrations/Version20180419190000.php} (54%) create mode 100644 app/inc/config.test.php create mode 100755 bin/doctrine diff --git a/.gitignore b/.gitignore index 69538d1..f98caa0 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 e56ec24..e95d0a2 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 d3e6237..8578437 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 0000000..dd79f96 --- /dev/null +++ b/app/classes/Framadate/AbstractMigration.php @@ -0,0 +1,54 @@ +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 bed6327..9d477d9 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 f8c3eac..0000000 --- a/app/classes/Framadate/Migration/AddColumn_hidden_In_poll_For_0_9.php +++ /dev/null @@ -1,75 +0,0 @@ -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 9863e26..0000000 --- a/app/classes/Framadate/Migration/AddColumn_receiveNewComments_For_0_9.php +++ /dev/null @@ -1,76 +0,0 @@ -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 2da2e49..0000000 --- a/app/classes/Framadate/Migration/AddColumn_uniqId_In_vote_For_0_9.php +++ /dev/null @@ -1,77 +0,0 @@ -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 93893a1..0000000 --- a/app/classes/Framadate/Migration/AddColumns_password_hash_And_results_publicly_visible_In_poll_For_0_9.php +++ /dev/null @@ -1,76 +0,0 @@ -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 6eae592..0000000 --- a/app/classes/Framadate/Migration/Fix_MySQL_No_Zero_Date.php +++ /dev/null @@ -1,70 +0,0 @@ -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 092de91..0000000 --- a/app/classes/Framadate/Migration/From_0_0_to_0_8_Migration.php +++ /dev/null @@ -1,108 +0,0 @@ -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 bb8ab78..0000000 --- a/app/classes/Framadate/Migration/From_0_8_to_0_9_Migration.php +++ /dev/null @@ -1,292 +0,0 @@ -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 fb81466..0000000 --- a/app/classes/Framadate/Migration/Generate_uniqId_for_old_votes.php +++ /dev/null @@ -1,80 +0,0 @@ -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 37eec25..0000000 --- a/app/classes/Framadate/Migration/Increase_pollId_size.php +++ /dev/null @@ -1,66 +0,0 @@ -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 52599eb..0000000 --- a/app/classes/Framadate/Migration/RPadVotes_from_0_8.php +++ /dev/null @@ -1,66 +0,0 @@ -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 0000000..afbf379 --- /dev/null +++ b/app/classes/Framadate/Migrations/Version20150101000000.php @@ -0,0 +1,99 @@ +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 0000000..46df4d9 --- /dev/null +++ b/app/classes/Framadate/Migrations/Version20150102000000.php @@ -0,0 +1,160 @@ +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 0000000..ae8ecfe --- /dev/null +++ b/app/classes/Framadate/Migrations/Version20150102100000.php @@ -0,0 +1,263 @@ +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 0000000..883d85c --- /dev/null +++ b/app/classes/Framadate/Migrations/Version20150117000000.php @@ -0,0 +1,70 @@ +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 0000000..08f5f18 --- /dev/null +++ b/app/classes/Framadate/Migrations/Version20150402000000.php @@ -0,0 +1,76 @@ +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 0000000..d03b624 --- /dev/null +++ b/app/classes/Framadate/Migrations/Version20150405000000.php @@ -0,0 +1,72 @@ +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 0000000..a71e056 --- /dev/null +++ b/app/classes/Framadate/Migrations/Version20150624000000.php @@ -0,0 +1,78 @@ +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 0000000..5b19768 --- /dev/null +++ b/app/classes/Framadate/Migrations/Version20150918000000.php @@ -0,0 +1,102 @@ +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 1844c81..e31ad61 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); + public function down(Schema $schema) + { + $commentTable = $schema->getTable(Utils::table('comment')); - return true; - } - - 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 afc57a9..919b0ba 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); + public function down(Schema $schema) + { + $commentTable = $schema->getTable(Utils::table('comment')); - return true; - } - - 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 0000000..af95745 --- /dev/null +++ b/app/classes/Framadate/Migrations/Version20151028000000.php @@ -0,0 +1,72 @@ +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 0000000..8b2f5b3 --- /dev/null +++ b/app/classes/Framadate/Migrations/Version20151205000000.php @@ -0,0 +1,51 @@ +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 8b1caa2..334a4d1 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 0000000..59dad11 --- /dev/null +++ b/app/classes/Framadate/Migrations/Version20180411000000.php @@ -0,0 +1,88 @@ +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 5ede344..8c9952f 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 65c9631..701b921 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 c4bed57..165a3ca 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 28a8b2f..fa7b752 100644 --- a/app/classes/Framadate/Repositories/AbstractRepository.php +++ b/app/classes/Framadate/Repositories/AbstractRepository.php @@ -1,43 +1,69 @@ 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 262ed0a..c122361 100644 --- a/app/classes/Framadate/Repositories/CommentRepository.php +++ b/app/classes/Framadate/Repositories/CommentRepository.php @@ -1,16 +1,16 @@ 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 8c1e7f4..4efda19 100644 --- a/app/classes/Framadate/Repositories/PollRepository.php +++ b/app/classes/Framadate/Repositories/PollRepository.php @@ -1,25 +1,45 @@ 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, + ]); } - 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]); - } - - 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 810d391..76910eb 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 4c9c40f..5139073 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 588a0ee..d7a362b 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 0f76150..02e3c99 100644 --- a/app/classes/Framadate/Services/AdminPollService.php +++ b/app/classes/Framadate/Services/AdminPollService.php @@ -1,10 +1,9 @@ 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 13672fa..ad7963d 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=;dbname=;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 f389cec..10d8e49 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 50c15df..92aecbe 100644 --- a/app/classes/Framadate/Services/PurgeService.php +++ b/app/classes/Framadate/Services/PurgeService.php @@ -1,6 +1,7 @@ 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 1f82f68..f106b6b 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 0000000..c642b2d --- /dev/null +++ b/app/inc/config.test.php @@ -0,0 +1,116 @@ +'; + +// 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 9950cfb..ed973be 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 487a72e..f67e7e7 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 8857951..e326df4 100644 --- a/app/tests/Framadate/Services/InputServiceUnitTest.php +++ b/app/tests/Framadate/Services/InputServiceUnitTest.php @@ -1,32 +1,35 @@ ["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 0000000..5bcd655 --- /dev/null +++ b/bin/doctrine @@ -0,0 +1,58 @@ +#!/usr/bin/env php +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 d19901f..dffa432 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 e855b8c..011f65d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,424 @@ "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/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/cache", + "version": "v1.6.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/eb152c5100571c7a45470ff2a35095ab3f3b900b", + "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b", + "shasum": "" + }, + "require": { + "php": "~5.5|~7.0" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "phpunit/phpunit": "~4.8|~5.0", + "predis/predis": "~1.0", + "satooshi/php-coveralls": "~0.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "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": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2017-07-22T12:49:21+00:00" + }, + { + "name": "doctrine/collections", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/1a4fb7e902202c33cce8c55989b945612943c2ba", + "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "doctrine/coding-standard": "~0.1@dev", + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Collections\\": "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": "Collections Abstraction library", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "array", + "collections", + "iterator" + ], + "time": "2017-01-03T10:49:41+00:00" + }, + { + "name": "doctrine/common", + "version": "v2.7.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/common.git", + "reference": "4acb8f89626baafede6ee5475bc5844096eba8a9" + }, + "dist": { + "type": "zip", + "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": "^5.4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "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 Library for Doctrine projects", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "collections", + "eventmanager", + "persistence", + "spl" + ], + "time": "2017-07-22T08:35:12+00:00" + }, + { + "name": "doctrine/dbal", + "version": "v2.5.13", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "729340d8d1eec8f01bff708e12e449a3415af873" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/729340d8d1eec8f01bff708e12e449a3415af873", + "reference": "729340d8d1eec8f01bff708e12e449a3415af873", + "shasum": "" + }, + "require": { + "doctrine/common": ">=2.4,<2.8-dev", + "php": ">=5.3.2" + }, + "require-dev": { + "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-0": { + "Doctrine\\DBAL\\": "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" + } + ], + "description": "Database Abstraction Layer", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "dbal", + "persistence", + "queryobject" + ], + "time": "2017-07-22T20:44:48+00:00" + }, + { + "name": "doctrine/inflector", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "90b2128806bfde671b6952ab8bea493942c1fdae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae", + "reference": "90b2128806bfde671b6952ab8bea493942c1fdae", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "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", @@ -61,17 +477,91 @@ "time": "2014-09-09T13:34:57+00:00" }, { - "name": "egulias/email-validator", - "version": "2.1.3", + "name": "doctrine/migrations", + "version": "v1.5.0", "source": { "type": "git", - "url": "https://github.com/egulias/EmailValidator.git", - "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04" + "url": "https://github.com/doctrine/migrations.git", + "reference": "c81147c0f2938a6566594455367e095150547f72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/1bec00a10039b823cc94eef4eddd47dcd3b2ca04", - "reference": "1bec00a10039b823cc94eef4eddd47dcd3b2ca04", + "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": { @@ -80,7 +570,7 @@ }, "require-dev": { "dominicsayers/isemail": "dev-master", - "phpunit/phpunit": "^4.8.35", + "phpunit/phpunit": "^4.8.35||^5.7||^6.0", "satooshi/php-coveralls": "^1.0.1" }, "suggest": { @@ -115,7 +605,7 @@ "validation", "validator" ], - "time": "2017-11-15T23:40:40+00:00" + "time": "2018-04-10T10:11:19+00:00" }, { "name": "erusev/parsedown", @@ -251,6 +741,69 @@ ], "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", @@ -328,18 +881,65 @@ "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", "version": "dev-master", "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", @@ -483,7 +1089,51 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2018-03-15T17:53:05+00:00" + "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", @@ -537,6 +1187,354 @@ "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": "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/yaml", + "version": "v3.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/a42f9da85c7c38d59f5e53f076fe81a091f894d0", + "reference": "a42f9da85c7c38d59f5e53f076fe81a091f894d0", + "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-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": [ + "code", + "zf2" + ], + "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", @@ -1554,53 +2491,6 @@ ], "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" - }, - "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": "sebastian/code-unit-reverse-lookup", "version": "1.0.1", @@ -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 206b592..b25832f 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 f63beb9..04a01b9 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 f63beb9..04a01b9 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 765131b..aade507 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 38f613c..d585bce 100644 --- a/tpl/admin/install.tpl +++ b/tpl/admin/install.tpl @@ -17,38 +17,53 @@ +

Le nom de l'application qui sera notamment utilisé dans les emails.

-
-
- - +
+
+
+
+ + +
+

L'adresse email de l'administrateur qui sera fournie en cas de souci.

+
+
+
+
+
+ + +
+

L'adresse de réponse des couriels envoyés par l'application.

+
-
-
- - +
+
+
+
+ + +
+
-
+
-
-
- - -
-
+
+ -
- - -
- +
+ +

Utiliser la réécriture d'URL pour obtenir de belles URLs.

+
+
@@ -56,38 +71,91 @@
{__('Installation', 'Database')} +
-
- - + {__('Installation', 'DbDriver')} +
+ +
+
+ +
+
+ +
+
+
+
+ + +
+

Le nom d'hôte du serveur de base de données, localhost si le serveur est le même.

+
+
+ +
+
+
+ + +
+

Port 3306 par défaut pour MySQL, 5432 pour PostgreSQL

+
- - + +
-
-
- - +
+
+
+
+ + +
+
+
+ +
+
+
+ + +
+
-
-
- - +
+
+
+
+ + +
+

Le préfixe à appliquer devant les tables

+
-
-
-
- - +
+
+
+ + +
+

La table utilisée pour stocker les migrations

+
diff --git a/tpl/admin/migration.tpl b/tpl/admin/migration.tpl index b508264..8930625 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} +
+
{$output}
+
+ {__('Generic', 'Page generated in')} {$time} {__('Generic', 'seconds')} +
+
+ {/if}
+
+

{__('Admin', 'Status')}

+ {if $countExecuted === $countTotal} +
+ No migrations to execute +
+ {else} +
+
+ +
+
+ {$countWaiting|html} migrations available. +
+ {/if} +

{__('Admin', 'Summary')}

- {__('Admin', 'Succeeded:')} {$countSucceeded|html} / {$countTotal|html} + {__('Admin', 'Waiting')} {$countWaiting|html} / {$countTotal|html}
- {__('Admin', 'Failed:')} {$countFailed|html} / {$countTotal|html} -
- {__('Admin', 'Skipped:')} {$countSkipped|html} / {$countTotal|html} -
-
-

{__('Admin', 'Success')}

-
    - {foreach $success as $s} -
  • {$s|html}
  • - {foreachelse} -
  • {__('Admin', 'Nothing')}
  • - {/foreach} -
-
- -
-

{__('Admin', 'Fail')}

-
    - {foreach $fail as $f} -
  • {$f|html}
  • - {foreachelse} -
  • {__('Admin', 'Nothing')}
  • - {/foreach} -
-
- -
- {__('Generic', 'Page generated in')} {$time} {__('Generic', 'seconds')} + {__('Admin', 'Executed')} {$countExecuted|html} / {$countTotal|html}
{/block} diff --git a/tpl/part/vote_table_classic.tpl b/tpl/part/vote_table_classic.tpl index aed5b91..aeda5fc 100644 --- a/tpl/part/vote_table_classic.tpl +++ b/tpl/part/vote_table_classic.tpl @@ -199,7 +199,7 @@ {foreach $slots as $id=>$slot}
    - {if $poll->ValueMax eq NULL || $best_choices['y'][$i] lt $poll->ValueMax} + {if $poll->valuemax eq NULL || $best_choices['y'][$i] lt $poll->valuemax}
    • - {if $poll->ValueMax eq NULL || $best_choices['y'][$i] lt $poll->ValueMax} + {if $poll->valuemax eq NULL || $best_choices['y'][$i] lt $poll->valuemax}