Skip to content

Commit

Permalink
Merge pull request #60 from Jamesking56/feature/postgresql-support
Browse files Browse the repository at this point in the history
PostgreSQL support
  • Loading branch information
freekmurze committed Jan 4, 2016
2 parents 410526b + 3ee2fc3 commit 963b63c
Show file tree
Hide file tree
Showing 6 changed files with 216 additions and 8 deletions.
4 changes: 2 additions & 2 deletions src/BackupHandlers/Database/DatabaseBackupHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public function getDatabase($connectionName = '')

$dbDriver = config("database.connections.{$connectionName}.driver");

if ($dbDriver != 'mysql') {
throw new Exception('laravel-backup can only backup mysql databases');
if ($dbDriver != 'mysql' && $dbDriver != 'pgsql') {
throw new Exception('laravel-backup can only backup mysql / pgsql databases');
}

return $this->databaseBuilder->getDatabase(config("database.connections.{$connectionName}"));
Expand Down
41 changes: 37 additions & 4 deletions src/BackupHandlers/Database/DatabaseBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,22 @@ public function __construct()

public function getDatabase(array $realConfig)
{
try {
$this->buildMySQL($realConfig);
} catch (Exception $e) {
throw new \Exception('Whoops, '.$e->getMessage());
switch($realConfig['driver']) {
case 'mysql':
try {
$this->buildMySQL($realConfig);
} catch (Exception $e) {
throw new \Exception('Whoops, '.$e->getMessage());
}
break;

case 'pgsql':
try {
$this->buildPgSql($realConfig);
} catch (Exception $e) {
throw new \Exception('Whoops, '.$e->getMessage());
}
break;
}

return $this->database;
Expand All @@ -43,6 +55,27 @@ protected function buildMySQL(array $config)
);
}

/**
* Build a PgSQLDatabase instance.
* @param array $config
*/
protected function buildPgSql(array $config)
{
$port = isset($config['port']) ? $config['port'] : 5432;

$schema = isset($config['schema']) ? $config['schema'] : 'public';

$this->database = new Databases\PgSQLDatabase(
$this->console,
$config['database'],
$schema,
$config['username'],
$config['password'],
$this->determineHost($config),
$port
);
}

/**
* Determine the host from the given config.
*
Expand Down
91 changes: 91 additions & 0 deletions src/BackupHandlers/Database/Databases/PgSQLDatabase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace Spatie\Backup\BackupHandlers\Database\Databases;

use Spatie\Backup\Console;

class PgSQLDatabase implements DatabaseInterface
{
protected $console;
protected $database;
protected $schema;
protected $username;
protected $password;
protected $host;
protected $port;

/**
* @param Console $console
* @param $database
* @param string $schema
* @param $username
* @param $password
* @param string $host
* @param int $port
* @param string $socket
*/
public function __construct(Console $console, $database, $schema, $username, $password, $host, $port)
{
$this->console = $console;
$this->database = $database;
$this->schema = $schema;
$this->username = $username;
$this->password = $password;
$this->host = $host;
$this->port = $port;
}

/**
* Create a database dump.
*
* @param $destinationFile
*
* @return bool
*/
public function dump($destinationFile)
{
$command = sprintf('export PGHOST && %spg_dump '.(!$this->useCopy() ? '--inserts' : '').' --schema=%s %s > %s',
$this->getDumpCommandPath(),
escapeshellarg($this->schema),
escapeshellarg($this->database),
escapeshellarg($destinationFile)
);

$env = [
'PGHOST' => $this->host,
'PGUSER' => $this->username,
'PGPASSWORD' => $this->password,
'PGPORT' => $this->port
];

return $this->console->run($command, config('laravel-backup.pgsql.timeoutInSeconds'), $env);
}

/**
* Return the file extension of a dump file (sql, ...).
*
* @return string
*/
public function getFileExtension()
{
return 'sql';
}

/**
* Get the path to the pgsql_dump.
*
* @return string
*/
protected function getDumpCommandPath()
{
return config('laravel-backup.pgsql.dump_command_path');
}

/**
* Determine if COPY should be used instead of INSERT.
*/
protected function useCopy()
{
return config('laravel-backup.pgsql.use_copy');
}
}
9 changes: 7 additions & 2 deletions src/Console.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,21 @@ class Console
* Run a command in the shell.
*
* @param $command
* @param $timeoutInSeconds
* @param int $timeoutInSeconds
* @param array $env
*
* @return bool|string
*/
public function run($command, $timeoutInSeconds = 60)
public function run($command, $timeoutInSeconds = 60, array $env = null)
{
$process = new Process($command);

$process->setTimeout($timeoutInSeconds);

if ($env != null) {
$process->setEnv($env);
}

$process->run();

if ($process->isSuccessful()) {
Expand Down
19 changes: 19 additions & 0 deletions src/config/laravel-backup.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,23 @@
*/
'timeoutInSeconds' => 60,
],

'pgsql' => [
/*
* The path to the pg_dump binary. You can leave this empty
* if the binary is installed in the default location.
*/
'dump_command_path' => '',

/*
* Set to true to use pgsql 'COPY' statements instead of 'INSERT's.
*/
'use_copy' => true,

/*
* If the dump of the db takes more seconds that the specified value,
* it will abort the backup.
*/
'timeoutInSeconds' => 60,
]
];
60 changes: 60 additions & 0 deletions tests/PgSQLDatabaseTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

use Mockery as m;
use Spatie\Backup\BackupHandlers\Database\Databases\PgSQLDatabase;

class PgSQLDatabaseTest extends Orchestra\Testbench\TestCase
{
protected $console;
protected $database;

public function setUp()
{
parent::setUp();

$this->console = m::mock('Spatie\Backup\Console');

$this->database = new PgSQLDatabase(
$this->console,
'testDatabase',
'public',
'testUser',
'password',
'localhost',
'5432'
);
}

public function tearDown()
{
m::close();
}

public function testFileExtension()
{
$this->assertEquals(
'sql', $this->database->getFileExtension()
);
}

public function testDump()
{
$this->console->shouldReceive('run')
->with(m::on(function ($parameter) {
$pattern = "/pg_dump --inserts --schema='public' 'testDatabase' > 'testfile.sql'/";

return preg_match($pattern, $parameter) == true;
}), null, [
'PGHOST' => 'localhost',
'PGUSER' => 'testUser',
'PGPASSWORD' => 'password',
'PGPORT' => '5432'
])
->once()
->andReturn(true);

$this->assertTrue(
$this->database->dump('testfile.sql')
);
}
}

0 comments on commit 963b63c

Please sign in to comment.