Extract DatabaseConfig class with validation

This commit is contained in:
Franz Liedke 2019-01-26 22:30:58 +01:00
parent 1e056b2c50
commit 7b2807a839
9 changed files with 161 additions and 106 deletions

View File

@ -12,10 +12,11 @@
namespace Flarum\Install\Console; namespace Flarum\Install\Console;
use Flarum\Install\AdminUser; use Flarum\Install\AdminUser;
use Flarum\Install\DatabaseConfig;
interface DataProviderInterface interface DataProviderInterface
{ {
public function getDatabaseConfiguration(); public function getDatabaseConfiguration(): DatabaseConfig;
public function getBaseUrl(); public function getBaseUrl();

View File

@ -13,6 +13,7 @@ namespace Flarum\Install\Console;
use Exception; use Exception;
use Flarum\Install\AdminUser; use Flarum\Install\AdminUser;
use Flarum\Install\DatabaseConfig;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Yaml\Yaml; use Symfony\Component\Yaml\Yaml;
@ -52,20 +53,17 @@ class FileDataProvider implements DataProviderInterface
} }
} }
public function getDatabaseConfiguration() public function getDatabaseConfiguration(): DatabaseConfig
{ {
return $this->databaseConfiguration + [ return new DatabaseConfig(
'driver' => 'mysql', $this->databaseConfiguration['driver'] ?? 'mysql',
'host' => 'localhost', $this->databaseConfiguration['host'] ?? 'localhost',
'database' => 'flarum', $this->databaseConfiguration['port'] ?? 3306,
'username' => 'root', $this->databaseConfiguration['database'] ?? 'flarum',
'password' => '', $this->databaseConfiguration['username'] ?? 'root',
'charset' => 'utf8mb4', $this->databaseConfiguration['password'] ?? '',
'collation' => 'utf8mb4_unicode_ci', $this->databaseConfiguration['prefix'] ?? ''
'prefix' => '', );
'port' => '3306',
'strict' => false,
];
} }
public function getBaseUrl() public function getBaseUrl()

View File

@ -11,12 +11,10 @@
namespace Flarum\Install\Console; namespace Flarum\Install\Console;
use Exception;
use Flarum\Console\AbstractCommand; use Flarum\Console\AbstractCommand;
use Flarum\Install\Installation; use Flarum\Install\Installation;
use Flarum\Install\Pipeline; use Flarum\Install\Pipeline;
use Flarum\Install\Step; use Flarum\Install\Step;
use Illuminate\Contracts\Validation\Factory;
use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputOption;
class InstallCommand extends AbstractCommand class InstallCommand extends AbstractCommand
@ -26,11 +24,6 @@ class InstallCommand extends AbstractCommand
*/ */
protected $installation; protected $installation;
/**
* @var Factory
*/
protected $validator;
/** /**
* @var DataProviderInterface * @var DataProviderInterface
*/ */
@ -38,12 +31,10 @@ class InstallCommand extends AbstractCommand
/** /**
* @param Installation $installation * @param Installation $installation
* @param Factory $validator
*/ */
public function __construct(Installation $installation, Factory $validator) public function __construct(Installation $installation)
{ {
$this->installation = $installation; $this->installation = $installation;
$this->validator = $validator;
parent::__construct(); parent::__construct();
} }
@ -98,32 +89,12 @@ class InstallCommand extends AbstractCommand
protected function install() protected function install()
{ {
$dbConfig = $this->dataSource->getDatabaseConfiguration();
$validation = $this->validator->make(
$dbConfig,
[
'driver' => 'required|in:mysql',
'host' => 'required',
'database' => 'required|string',
'username' => 'required|string',
'prefix' => 'nullable|alpha_dash|max:10',
'port' => 'nullable|integer|min:1|max:65535',
]
);
if ($validation->fails()) {
throw new Exception(implode("\n",
call_user_func_array('array_merge',
$validation->getMessageBag()->toArray())));
}
$this->runPipeline( $this->runPipeline(
$this->installation $this->installation
->configPath($this->input->getOption('config')) ->configPath($this->input->getOption('config'))
->debugMode($this->dataSource->isDebugMode()) ->debugMode($this->dataSource->isDebugMode())
->baseUrl($this->dataSource->getBaseUrl()) ->baseUrl($this->dataSource->getBaseUrl())
->databaseConfig($dbConfig) ->databaseConfig($this->dataSource->getDatabaseConfiguration())
->adminUser($this->dataSource->getAdminUser()) ->adminUser($this->dataSource->getAdminUser())
->settings($this->dataSource->getSettings()) ->settings($this->dataSource->getSettings())
->build() ->build()

View File

@ -12,6 +12,7 @@
namespace Flarum\Install\Console; namespace Flarum\Install\Console;
use Flarum\Install\AdminUser; use Flarum\Install\AdminUser;
use Flarum\Install\DatabaseConfig;
use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Helper\QuestionHelper;
use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Output\OutputInterface;
@ -34,27 +35,24 @@ class UserDataProvider implements DataProviderInterface
$this->questionHelper = $questionHelper; $this->questionHelper = $questionHelper;
} }
public function getDatabaseConfiguration() public function getDatabaseConfiguration(): DatabaseConfig
{ {
$host = $this->ask('Database host:'); $host = $this->ask('Database host:');
$port = '3306'; $port = 3306;
if (str_contains($host, ':')) { if (str_contains($host, ':')) {
list($host, $port) = explode(':', $host, 2); list($host, $port) = explode(':', $host, 2);
} }
return [ return new DatabaseConfig(
'driver' => 'mysql', 'mysql',
'host' => $host, $host,
'port' => $port, intval($port),
'database' => $this->ask('Database name:'), $this->ask('Database name:'),
'username' => $this->ask('Database user:'), $this->ask('Database user:'),
'password' => $this->secret('Database password:'), $this->secret('Database password:'),
'charset' => 'utf8mb4', $this->ask('Prefix:')
'collation' => 'utf8mb4_unicode_ci', );
'prefix' => $this->ask('Prefix:'),
'strict' => false,
];
} }
public function getBaseUrl() public function getBaseUrl()

View File

@ -13,6 +13,7 @@ namespace Flarum\Install\Controller;
use Flarum\Http\SessionAuthenticator; use Flarum\Http\SessionAuthenticator;
use Flarum\Install\AdminUser; use Flarum\Install\AdminUser;
use Flarum\Install\DatabaseConfig;
use Flarum\Install\Installation; use Flarum\Install\Installation;
use Flarum\Install\StepFailed; use Flarum\Install\StepFailed;
use Flarum\Install\ValidationFailed; use Flarum\Install\ValidationFailed;
@ -51,31 +52,12 @@ class InstallController implements RequestHandlerInterface
public function handle(Request $request): ResponseInterface public function handle(Request $request): ResponseInterface
{ {
$input = $request->getParsedBody(); $input = $request->getParsedBody();
$host = array_get($input, 'mysqlHost');
$port = '3306';
if (str_contains($host, ':')) {
list($host, $port) = explode(':', $host, 2);
}
$baseUrl = rtrim((string) $request->getUri(), '/'); $baseUrl = rtrim((string) $request->getUri(), '/');
try { try {
$pipeline = $this->installation $pipeline = $this->installation
->baseUrl($baseUrl) ->baseUrl($baseUrl)
->databaseConfig([ ->databaseConfig($this->makeDatabaseConfig($input))
'driver' => 'mysql',
'host' => $host,
'port' => $port,
'database' => array_get($input, 'mysqlDatabase'),
'username' => array_get($input, 'mysqlUsername'),
'password' => array_get($input, 'mysqlPassword'),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => array_get($input, 'tablePrefix'),
'strict' => false,
])
->adminUser($this->makeAdminUser($input)) ->adminUser($this->makeAdminUser($input))
->settings([ ->settings([
'forum_title' => array_get($input, 'forumTitle'), 'forum_title' => array_get($input, 'forumTitle'),
@ -99,6 +81,26 @@ class InstallController implements RequestHandlerInterface
return new Response\EmptyResponse; return new Response\EmptyResponse;
} }
private function makeDatabaseConfig(array $input): DatabaseConfig
{
$host = array_get($input, 'mysqlHost');
$port = 3306;
if (str_contains($host, ':')) {
list($host, $port) = explode(':', $host, 2);
}
return new DatabaseConfig(
'mysql',
$host,
intval($port),
array_get($input, 'mysqlDatabase'),
array_get($input, 'mysqlUsername'),
array_get($input, 'mysqlPassword'),
array_get($input, 'tablePrefix')
);
}
/** /**
* @param array $input * @param array $input
* @return AdminUser * @return AdminUser

View File

@ -0,0 +1,98 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Install;
class DatabaseConfig
{
private $driver;
private $host;
private $port;
private $database;
private $username;
private $password;
private $prefix;
public function __construct($driver, $host, $port, $database, $username, $password, $prefix)
{
$this->driver = $driver;
$this->host = $host;
$this->port = $port;
$this->database = $database;
$this->username = $username;
$this->password = $password;
$this->prefix = $prefix;
$this->validate();
}
public function getConfig(): array
{
return [
'driver' => $this->driver,
'host' => $this->host,
'port' => $this->port,
'database' => $this->database,
'username' => $this->username,
'password' => $this->password,
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => $this->prefix,
'strict' => false,
'engine' => 'InnoDB',
];
}
private function validate()
{
if (empty($this->driver)) {
throw new ValidationFailed('Please specify a database driver.');
}
if ($this->driver !== 'mysql') {
throw new ValidationFailed('Currently, only MySQL/MariaDB is supported.');
}
if (empty($this->host)) {
throw new ValidationFailed('Please specify the hostname of your database server.');
}
if (! is_int($this->port) || $this->port < 1 || $this->port > 65535) {
throw new ValidationFailed('Please provide a valid port number between 1 and 65535.');
}
if (empty($this->database)) {
throw new ValidationFailed('Please specify the database name.');
}
if (! is_string($this->database)) {
throw new ValidationFailed('The database name must be a non-empty string.');
}
if (empty($this->username)) {
throw new ValidationFailed('Please specify the username for accessing the database.');
}
if (! is_string($this->database)) {
throw new ValidationFailed('The username must be a non-empty string.');
}
if (! empty($this->prefix)) {
if (! preg_match('/^[\pL\pM\pN_-]+$/u', $this->prefix)) {
throw new ValidationFailed('The prefix may only contain characters, dashes and underscores.');
}
if (strlen($this->prefix) > 10) {
throw new ValidationFailed('The prefix should be no longer than 10 characters.');
}
}
}
}

View File

@ -19,10 +19,12 @@ class Installation
private $configPath; private $configPath;
private $debug = false; private $debug = false;
private $dbConfig = [];
private $baseUrl; private $baseUrl;
private $customSettings = []; private $customSettings = [];
/** @var DatabaseConfig */
private $dbConfig;
/** @var AdminUser */ /** @var AdminUser */
private $adminUser; private $adminUser;
@ -54,7 +56,7 @@ class Installation
return $this; return $this;
} }
public function databaseConfig(array $dbConfig) public function databaseConfig(DatabaseConfig $dbConfig)
{ {
$this->dbConfig = $dbConfig; $this->dbConfig = $dbConfig;

View File

@ -11,6 +11,7 @@
namespace Flarum\Install\Steps; namespace Flarum\Install\Steps;
use Flarum\Install\DatabaseConfig;
use Flarum\Install\Step; use Flarum\Install\Step;
use Illuminate\Database\Connectors\MySqlConnector; use Illuminate\Database\Connectors\MySqlConnector;
use Illuminate\Database\MySqlConnection; use Illuminate\Database\MySqlConnection;
@ -22,11 +23,9 @@ class ConnectToDatabase implements Step
private $dbConfig; private $dbConfig;
private $store; private $store;
public function __construct($dbConfig, callable $store) public function __construct(DatabaseConfig $dbConfig, callable $store)
{ {
$this->dbConfig = $dbConfig; $this->dbConfig = $dbConfig;
$this->dbConfig['engine'] = 'InnoDB';
$this->store = $store; $this->store = $store;
} }
@ -37,7 +36,8 @@ class ConnectToDatabase implements Step
public function run() public function run()
{ {
$pdo = (new MySqlConnector)->connect($this->dbConfig); $config = $this->dbConfig->getConfig();
$pdo = (new MySqlConnector)->connect($config);
$version = $pdo->getAttribute(PDO::ATTR_SERVER_VERSION); $version = $pdo->getAttribute(PDO::ATTR_SERVER_VERSION);
@ -48,9 +48,9 @@ class ConnectToDatabase implements Step
($this->store)( ($this->store)(
new MySqlConnection( new MySqlConnection(
$pdo, $pdo,
$this->dbConfig['database'], $config['database'],
$this->dbConfig['prefix'], $config['prefix'],
$this->dbConfig $config
) )
); );
} }

View File

@ -11,6 +11,7 @@
namespace Flarum\Install\Steps; namespace Flarum\Install\Steps;
use Flarum\Install\DatabaseConfig;
use Flarum\Install\ReversibleStep; use Flarum\Install\ReversibleStep;
use Flarum\Install\Step; use Flarum\Install\Step;
@ -24,7 +25,7 @@ class StoreConfig implements Step, ReversibleStep
private $configFile; private $configFile;
public function __construct($debugMode, $dbConfig, $baseUrl, $configFile) public function __construct($debugMode, DatabaseConfig $dbConfig, $baseUrl, $configFile)
{ {
$this->debugMode = $debugMode; $this->debugMode = $debugMode;
$this->dbConfig = $dbConfig; $this->dbConfig = $dbConfig;
@ -55,28 +56,12 @@ class StoreConfig implements Step, ReversibleStep
{ {
return [ return [
'debug' => $this->debugMode, 'debug' => $this->debugMode,
'database' => $this->getDatabaseConfig(), 'database' => $this->dbConfig->getConfig(),
'url' => $this->baseUrl, 'url' => $this->baseUrl,
'paths' => $this->getPathsConfig(), 'paths' => $this->getPathsConfig(),
]; ];
} }
private function getDatabaseConfig()
{
return [
'driver' => $this->dbConfig['driver'],
'host' => $this->dbConfig['host'],
'database' => $this->dbConfig['database'],
'username' => $this->dbConfig['username'],
'password' => $this->dbConfig['password'],
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => $this->dbConfig['prefix'],
'port' => $this->dbConfig['port'],
'strict' => false,
];
}
private function getPathsConfig() private function getPathsConfig()
{ {
return [ return [