Symfony - Лучшая практика для сброса базы данных - PullRequest
3 голосов
/ 06 июня 2019

Я работаю над проектом Symfony 4.2 и ищу лучшую практику для сброса базы данных, когда администратору нужно сделать это с помощью кнопки в backoffice.

Объяснение:

Проект представляет собой временное событие веб-сайт.Это означает, что люди будут посещать веб-сайт только в течение дня / недели, а затем веб-сайт будет отключен.Например, веб-сайт для зрителей, выходящих на стадион во время баскетбольного турнира.

По окончании турнира администратор хотел бы сбросить все данные, отправленные во время него, с помощью кнопки.

Прямо сейчасЯ сделал это так, но я не знаю, лучше ли это в производственной среде.

Я создал сервис, который получает KernelInterface в конструкторе:

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();
}

Во-первых, это так?хорошо это делать в производственных условиях?(Никто другой администратор не будет использовать веб-сайт при выполнении этой операции)

Во-вторых, я не очень удовлетворен методом, который я использовал, чтобы проверить, была ли операция успешно выполнена (strpos($responseCreate, 'successfully') !== false).Кто-нибудь знает лучший способ?

Большое спасибо за вашу помощь

Ответы [ 3 ]

2 голосов
/ 06 июня 2019

Если это работает для вас, все в порядке. Об «успешной» проверке части. Просто поместите ваш звонок в блок try-catch и проверьте наличие исключений. Если исключение не возникло, предположим, что оно выполнено успешно.

$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);
}

Достаточно ли хорош PostgreSQL для транзакций DDL? Принудительное выполнение транзакции:

$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();
0 голосов
/ 07 июня 2019

Во-первых, хорошо ли так делать в производственной среде?

Я так не думаю! Например, приведенные ниже команды будут предупреждатьВы с: [CAUTION] This operation should not be executed in a production environment!.Однако в мире дикого программирования все возможно, как показано ниже.

Попробуйте Symfony Компонент процесса .

Это базовый пример, так что вам решать, как это сделать.очиститель и дублирование бесплатно.Я проверил, и это работает.Вы также можете транслировать вывод.

# 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 голосов
/ 06 июня 2019

Я не уверен в том, как вы выполняете команды, но есть одна альтернатива, которую стоит рассмотреть, используя DoctrineFixturesBundle. Вам необходимо установить его для использования в производственной среде (технически это не рекомендуется, я думаю из-за риска удаления данных продукта, но это то, что вы хотите сделать).

Установка:

$ composer require doctrine/doctrine-fixtures-bundle

Config:

// config/bundles.php

return [
  ...
  Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['all' => true],
  ...
];

Вам необходимо создать прибор , и он должен иметь метод load(), совместимый с Doctrine \ Common \ DataFixtures \ FixtureInterface :: load (Doctrine \ Common \ Persistence \ ObjectManager $ manager) , но он может быть пустым, как показано ниже:

<?php // src/DataFixtures/AppFixtures.php

namespace App\DataFixtures;

use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Common\Persistence\ObjectManager;

class AppFixtures extends Fixture
{
  public function load(ObjectManager $manager){}
}

Команда:

$ php bin/console doctrine:fixtures:load -n --purge-with-truncate  --env=prod

Справка:

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