MigrationCommand.php 8.5 KB
Newer Older
1 2
<?php

3
namespace App\Command;
4

5
use App\Document\GoGoLogUpdate;
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
6 7
use App\Document\MigrationState;
use App\Services\AsyncService;
8 9
use Doctrine\ODM\MongoDB\DocumentManager;
use Psr\Log\LoggerInterface;
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
10 11 12
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Process\Process;
13 14
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

15 16
/**
 * Command to update database when schema need migration
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
17
 * Also provide some update message in the admin dashboard.
18 19 20
 */
class MigrationCommand extends GoGoAbstractCommand
{
Sebastian Castro's avatar
Sebastian Castro committed
21 22 23
    // -----------------------------------------------------------------
    // DO NOT REMOVE A SINGLE ELEMENT OF THOSE ARRAYS, ONLY ADD NEW ONES
    // -----------------------------------------------------------------
Alan Poulain's avatar
Alan Poulain committed
24
    public static $migrations = [
25
      // v2.4.6
Sebastian Castro's avatar
Sebastian Castro committed
26 27 28 29 30 31
      'db.TileLayer.updateMany({name:"cartodb"}, {$set: {attribution:"&copy; <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a> &copy; <a href=\"http://cartodb.com/attributions\">CartoDB</a>"}})',
      'db.TileLayer.updateMany({name:"hydda"}, {$set: {attribution:"Tiles courtesy of <a href=\"http://openstreetmap.se/\" target=\"_blank\">OpenStreetMap Sweden</a> &mdash; Map data &copy; <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>"}})',
      'db.TileLayer.updateMany({name:"wikimedia"}, {$set: {attribution:"<a href=\"https://wikimediafoundation.org/wiki/Maps_Terms_of_Use\">Wikimedia</a> | Map data © <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap contributors</a>"}})',
      'db.TileLayer.updateMany({name:"lyrk"}, {$set: {attribution:"&copy Lyrk | Map data &copy; <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>"}})',
      'db.TileLayer.updateMany({name:"osmfr"}, {$set: {attribution:"&copy; Openstreetmap France | &copy; <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>"}})',
      'db.TileLayer.updateMany({name:"stamenWaterColor"}, {$set: {attribution:"Map tiles by <a href=\"http://stamen.com\">Stamen Design</a>, <a href=\"http://creativecommons.org/licenses/by/3.0\">CC BY 3.0</a> &mdash; Map data &copy; <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>"}})',
Sebastian Castro's avatar
Sebastian Castro committed
32 33
    ];

Alan Poulain's avatar
Alan Poulain committed
34
    public static $commands = [
Sebastian Castro's avatar
Sebastian Castro committed
35
      // v2.3.1
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
36
      'app:elements:updateJson all',
Sebastian Castro's avatar
Sebastian Castro committed
37
      // v2.3.4
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
38
      'app:elements:updateJson all',
Sebastian Castro's avatar
Sebastian Castro committed
39
      // v2.4.5
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
40
      'app:elements:updateJson all',
Sebastian Castro's avatar
Sebastian Castro committed
41 42
    ];

Alan Poulain's avatar
Alan Poulain committed
43
    public static $messages = [
Sebastian Castro's avatar
Sebastian Castro committed
44
        // v2.3.0
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
45
        'Un champ <b>Image (url)</b> est maintenant disponible dans la confiugration du formulaire !',
Sebastian Castro's avatar
Sebastian Castro committed
46 47 48
        "Vous pouvez désormais customizer la popup qui s'affiche au survol d'un marqueur. Allez dans Personnalisation -> Marqueur / Popup",
        "Nouvelle option pour le menu (Personnalisation -> La Carte -> onglet Menu) : afficher à côté de chaque catégories le nombre d'élements disponible pour cette catégorie",
        // v2.3.1
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
49
        'Vous pouvez maintenant renseigner la licence qui protège vos données dans Personnalisation -> Configuration Générale',
Sebastian Castro's avatar
Sebastian Castro committed
50
        // v2.3.4
Sebastian Castro's avatar
Sebastian Castro committed
51 52
        "Amélioration du <b>système d'import</b>: vous pouvez maintenant faire correspondre les champs et les catégories avant d'importer. Des vidéos tutoriels ont été réalisés. <u>Merci de parcourir vos imports dynamiques pour les mettre à jour avec le nouveau système</u>",
        "<b>La gestion des permissions des utilisateurs fait peau neuve !</b> <u>Votre ancienne configuration ne sera peut être plus valide</u>. Veuillez vous rendre dans le <b>menu Utilisateurs pour mettre à jour les roles des utilisateurs et des groupes</b> d'utilisateurs.",
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
53
        'Vous pouvez maintenant configurer des mot clés à exclure dans la recherche des éléments. Rendez-vous dans Personnalisation -> La Carte -> Onglet Recherche',
Sebastian Castro's avatar
Sebastian Castro committed
54
        // v2.5
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
55
        "Il est maintenant possible de <b>téléverser des images et des fichiers</b> depuis le formulaire d'ajout d'un élément ! Paramétrez ces nouveaux champs dans Modèle de Données -> Formulaire",
56
        // v3.0
Sebastian Castro's avatar
Sebastian Castro committed
57 58
        "Vous pouvez maintenant écrire des actualités qui seront incluses dans la newsletter automatique! Allez dans Mails/Newsletter -> Actualités",
        "L'export des éléments depuis la page Données -> Elements fonctionne de nouveau et inclus cette fois correctement tous les champs personnalisés (y compris fichiers et images)"
Sebastian Castro's avatar
Sebastian Castro committed
59 60
    ];

61 62 63 64 65 66 67
    public function __construct(DocumentManager $dm, LoggerInterface $commandsLogger,
                               TokenStorageInterface $security,
                               AsyncService $asyncService)
    {
        $this->asyncService = $asyncService;
        parent::__construct($dm, $commandsLogger, $security);
    }
Sebastian Castro's avatar
Sebastian Castro committed
68

Alan Poulain's avatar
Alan Poulain committed
69
    protected function gogoConfigure(): void
70 71 72 73 74
    {
        $this->setName('db:migrate')
             ->setDescription('Update datatabse each time after code update');
    }

Alan Poulain's avatar
Alan Poulain committed
75
    protected function gogoExecute(DocumentManager $dm, InputInterface $input, OutputInterface $output): void
76
    {
77
        $migrationState = $dm->createQueryBuilder('App\Document\MigrationState')->getQuery()->getSingleResult();
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
78
        if (null == $migrationState) { // Meaning the migration state was not yet in the place in the code
79
            $migrationState = new MigrationState();
Sebastian Castro's avatar
Sebastian Castro committed
80
            $dm->persist($migrationState);
81 82
        }

83 84 85
        try {
            // Collecting the Database to be updated
            $dbs = ['gogocarto_default'];
86
            $dbNames = $dm->createQueryBuilder('App\Document\Project')->select('domainName')->hydrate(false)->getQuery()->execute()->toArray();
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
87 88 89
            foreach ($dbNames as $object) {
                $dbs[] = $object['domainName'];
            }
90

Alan Poulain's avatar
Alan Poulain committed
91 92
            if (count(self::$migrations) > $migrationState->getMigrationIndex()) {
                $migrationsToRun = array_slice(self::$migrations, $migrationState->getMigrationIndex());
Sebastian Castro's avatar
Sebastian Castro committed
93
                $migrationsToRun = array_unique($migrationsToRun);
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
94 95 96
                foreach ($dbs as $db) {
                    foreach ($migrationsToRun as $migration) {
                        $this->log('run migration '.$migration.' on project '.$db);
Sebastian Castro's avatar
Sebastian Castro committed
97
                        $this->runMongoCommand($db, $migration);
98
                    }
99
                }
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
100
                $this->log(count($migrationsToRun).' migrations performed');
101
            } else {
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
102
                $this->log('No Migrations to perform');
103 104
            }

105
            // run them syncronously otherwise all the command will be run at once
106
            $this->asyncService->setRunSynchronously(true);
Alan Poulain's avatar
Alan Poulain committed
107 108
            if (count(self::$commands) > $migrationState->getCommandsIndex()) {
                $commandsToRun = array_slice(self::$commands, $migrationState->getCommandsIndex());
109
                $commandsToRun = array_unique($commandsToRun);
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
110 111 112 113
                $this->log(count($commandsToRun).' commands to run');
                foreach ($dbs as $db) {
                    foreach ($commandsToRun as $command) {
                        $this->log('call command '.$command.' on project '.$db);
114
                        $this->asyncService->callCommand($command, [], $db);
115
                    }
116 117
                }
            } else {
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
118
                $this->log('No commands to run');
Sebastian Castro's avatar
Sebastian Castro committed
119 120
            }

Alan Poulain's avatar
Alan Poulain committed
121 122
            if (count(self::$messages) > $migrationState->getMessagesIndex()) {
                $messagesToAdd = array_slice(self::$messages, $migrationState->getMessagesIndex());
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
123 124 125 126
                $this->log(count($messagesToAdd).' messages to add');
                foreach ($dbs as $db) {
                    $this->log('add message on project '.$db);
                    foreach ($messagesToAdd as $message) {
127
                        // create a GoGoLogUpdate
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
128
                        $this->asyncService->callCommand('gogolog:add:message', ['"'.$message.'"'], $db);
129
                    }
130
                }
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
131
                $this->log(count($messagesToAdd).' messages added to admin dashboard');
132
            } else {
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
133
                $this->log('No Messages to add to dashboard');
134
            }
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
135 136 137
        } catch (\Exception $e) {
            $message = $e->getMessage().'</br>'.$e->getFile().' LINE '.$e->getLine();
            $this->error('Error performing migrations: '.$message);
138
        }
139

Alan Poulain's avatar
Alan Poulain committed
140 141 142
        $migrationState->setMigrationIndex(count(self::$migrations));
        $migrationState->setCommandsIndex(count(self::$commands));
        $migrationState->setMessagesIndex(count(self::$messages));
Sebastian Castro's avatar
Sebastian Castro committed
143
        $dm->flush();
144 145
    }

Sebastian Castro's avatar
Sebastian Castro committed
146
    private function runMongoCommand($db, $command)
147
    {
Sebastian Castro's avatar
Sebastian Castro committed
148
        $process = new Process("mongo {$db} --eval '{$command}'");
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
149

150
        return $process->run();
151
    }
Alan Poulain's avatar
Fix CS  
Alan Poulain committed
152
}