Symfony-重置数据库的最佳实践

时间:2019-06-06 14:04:40

标签: php symfony symfony4 symfony-console

我正在研究Symfony 4.2项目,当管理员需要通过后台的按钮来完成数据库重置时,我正在寻找最佳实践。

说明:

该项目是一个临时事件网站。 这意味着,人们将只访问该网站一天/一周,然后该网站关闭。例如,篮球比赛期间观众进入体育场的网站。

比赛结束后,管理员想通过按钮重置在此期间发送的所有数据。

现在我是这样做的,但是我不知道这在生产环境中是否是更好的方法。

我创建了一个在构造函数中获取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 个答案:

答案 0 :(得分:1)

如果它对您有用,就可以了。关于“成功”检查部分。只需将您的呼叫放在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();

答案 1 :(得分:0)

我不确定您执行命令的方式,但是使用DoctrineFixturesBundle可以考虑使用单个命令替代方法。您需要安装它以在生产环境中使用(出于技术上的考虑,不建议这样做,因为删除产品数据有风险,但这就是您要执行的操作。)

安装:

$ composer require doctrine/doctrine-fixtures-bundle

配置:

// config/bundles.php

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

您确实需要create a fixture,并且它必须具有与Doctrine \ Common \ DataFixtures \ FixtureInterface :: load(Doctrine \ Common \ Persistence \ ObjectManager $ manager)兼容的load()方法,但是可以完全是空的,如下所示:

<?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

答案 2 :(得分:0)

  

首先,在生产环境中这样做会很好吗?

我不这么认为!例如,以下命令将警告您:[CAUTION] This operation should not be executed in a production environment!。但是,如下所示,在狂野的编程世界中,一切皆有可能。

尝试Symfony的The Process Component

这是基本示例,因此您可以使其变得更整洁且无重复。我测试了并且可以用。您也可以流式传输输出。

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