3
votes

Symfony - Meilleures pratiques pour réinitialiser la base de données

Je travaille sur un projet Symfony 4.2 et je recherche les meilleures pratiques pour réaliser une réinitialisation de la base de données lorsque l'administrateur doit le faire via un bouton dans le backoffice.

Explication:

Le projet est un site Web événement temporaire . Cela signifie que les gens ne visiteront le site Web que pendant un jour / une semaine, puis le site Web sera désactivé. Par exemple, un site Web pour les spectateurs dans un stade lors d'un tournoi de basket.

Lorsque le tournoi est terminé, l'administrateur souhaite réinitialiser toutes les données envoyées pendant celui-ci via un bouton.

En ce moment, je l'ai fait comme ça mais je ne sais pas si c'est la meilleure façon dans l'environnement de production.

J'ai créé un service qui récupère KernelInterface dans le constructeur:

public function resetDB() {

    $application = new Application($this->kernel);
    $application->setAutoExit(false);

    $input = new ArrayInput([
        'command'   => 'doctrine:schema:drop',
        '--force' => true
    ]);

    $output = new BufferedOutput();
    $application->run($input, $output);

    $responseDrop = $output->fetch();

    if (strpos($responseDrop, 'successfully') !== false) {
        $input = new ArrayInput([
            'command'   => 'doctrine:schema:create',
        ]);

        $application->run($input, $output);

        $responseCreate = $output->fetch();

        if (strpos($responseCreate, 'successfully') !== false)
            return new Response();
    }

    return new \ErrorException();
}


0 commentaires

3 Réponses :


2
votes

Si cela fonctionne pour vous, c'est ok. À propos de la partie de contrôle «réussie». Entourez simplement votre appel dans un bloc try-catch et vérifiez les exceptions. Si aucune exception n'a été levée, supposez qu'elle s'est exécutée avec succès.

$application = new Application($this->kernel);
$application->setAutoExit(false);

// in case of any SQL error
// an exception will be thrown
$this->entityManager->transactional(function () use ($application) {
    $application->run(
        new StringInput('doctrine:schema:drop --force'),
        new DummyOutput()
    );

    $application->run(
        new StringInput('doctrine:schema:create'),
        new DummyOutput()
    );
});

return new Response();

PostgreSQL est-il assez bon pour les transactions DDL? Forcer une transaction alors:

$application = new Application($this->kernel);
$application->setAutoExit(false);

try {
    $application->run(
        new StringInput('doctrine:schema:drop --force'),
        new DummyOutput()
    );

    $application->run(
        new StringInput('doctrine:schema:create'),
        new DummyOutput()
    );

    return new Response();
} catch (\Exception $exception) {
    // don't throw exceptions, use proper responses
    // or do whatever you want

    return new Response('', Response::HTTP_INTERNAL_SERVER_ERROR);
}


7 commentaires

Salut @emix, je ne sais pas quelle est la meilleure solution entre celle que j'ai donnée ou celle de TRUNCATE sur chaque table (actuellement 15 tables en base de données). J'ai une base de données postgre, donc un peu difficile que la base de données mysql à faire TRUNCATE


Vous pouvez alors vous en tenir à la suppression du schéma et le recréer.


J'ai essayé la deuxième méthode avec transactionnel mais je récupère toujours un HTTP 200. J'ai commenté la baisse, donc il essaie de créer la base de données mais elle est déjà créée. Il devrait envoyer un HTTP 500 mais ce n'est pas le cas. Peut-être que la transaction fonctionne lors de la modification des entités et de leur vidage, mais pas avec une commande de console?


Si vous obtenez 200, tout fonctionne bien. Ne recrée-t-il pas des tableaux? Vous pouvez simuler l'erreur en lançant une exception dans la fonction anonyme transactionnelle.


Enfin, j'ai utilisé votre premier exemple mais j'ai vérifié la sortie de $ application-> run pour savoir si l'opération a fonctionné avec succès car elle n'a envoyé aucune erreur (elle renvoie une chaîne). $ application-> run (new StringInput ('doctrine: schema: drop --force'), $ output = new BufferedOutput ()); if (strpos ($ output-> fetch (), 'avec succès')! == false) {$ application-> run (new StringInput ('doctrine: schema: create'), $ output = new BufferedOutput ()); < / code>


Je ne pense pas que ce soit nécessaire à aucun moment. En cas d'erreur, vous obtiendrez une exception provenant de la commande exécutée.


J'ai essayé mais non, il ne récupère aucune exception. Ce que j'ai essayé: j'ai commenté le drop donc il essaie de créer mais c'est déjà le cas. Lorsque j'ai vidé la sortie, je peux voir l'exception dans une chaîne. C'est pourquoi je dois faire le check avec strpos car on récupère une chaîne



1
votes

Je ne suis pas sûr de la manière dont vous exécutez les commandes, mais il y a une seule alternative de commande à considérer, en utilisant DoctrineFixturesBundle. Vous devez l'installer pour une utilisation dans l'environnement de production (techniquement non recommandé, je pense à cause du risque de suppression des données de production, mais c'est ce que vous voulez faire).

Installer:

$ php bin/console doctrine:fixtures:load --help


0 commentaires

0
votes

Premièrement, est-il bon de le faire comme ça dans un environnement de production?

Je ne pense pas! Par exemple, les commandes ci-dessous vous avertiraient avec: [ATTENTION] Cette opération ne doit pas être exécutée dans un environnement de production! . Cependant, tout est possible dans le monde de la programmation sauvage comme indiqué ci-dessous.

Essayez Symfony Le composant de processus .

Ceci est l'exemple de base, c'est donc à vous de le rendre plus propre et sans duplication. J'ai testé et ça marche. Vous pouvez également diffuser la sortie.

# DROP IT
$process = new Process(
    ['/absolute/path/to/project/bin/console', 'doctrine:schema:drop', '--force', '--no-interaction']
);
$process->run();
if (!$process->isSuccessful()) {
    throw new ProcessFailedException($process);
}

# RECREATE IT    
$process = new Process(
    ['/absolute/path/to/project/bin/console', 'doctrine:schema:update', '--force', '--no-interaction']
);
$process->run();
if (!$process->isSuccessful()) {
    throw new ProcessFailedException($process);
}

0 commentaires