Skip to content

Commit 5707c46

Browse files
authored
Merge pull request #151 from joomlatools/feature/149-export
Add site:export and database:dump commands
2 parents 12b6f23 + dd7bbc6 commit 5707c46

File tree

9 files changed

+108
-112
lines changed

9 files changed

+108
-112
lines changed

src/Joomlatools/Console/Application.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ protected function getDefaultCommands()
125125
$commands = array_merge($commands, array(
126126
new Command\Database\Install(),
127127
new Command\Database\Drop(),
128-
new Command\Database\Dump(),
128+
new Command\Database\Export(),
129129

130130
new Command\Extension\Install(),
131131
new Command\Extension\Register(),

src/Joomlatools/Console/Command/Database/AbstractDatabase.php

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,6 @@ protected function configure()
6565
"MySQL driver",
6666
'mysqli'
6767
)
68-
->addOption(
69-
// @TODO To be removed in 1.6
70-
'mysql_db_prefix',
71-
null,
72-
InputOption::VALUE_REQUIRED,
73-
"[DEPRECATED] MySQL database prefix"
74-
)
7568
;
7669
}
7770

@@ -82,7 +75,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
8275
$db_name = $input->getOption('mysql-database');
8376
if (empty($db_name))
8477
{
85-
$this->target_db_prefix = $input->getOption('mysql_db_prefix') ?: $input->getOption('mysql-db-prefix');
78+
$this->target_db_prefix = $input->getOption('mysql-db-prefix');
8679
$this->target_db = $this->target_db_prefix.$this->site;
8780
}
8881
else
@@ -110,21 +103,69 @@ protected function execute(InputInterface $input, OutputInterface $output)
110103

111104
protected function _backupDatabase($target_file)
112105
{
113-
$password = empty($this->mysql->password) ? '' : sprintf("-p'%s'", $this->mysql->password);
106+
$this->_executeMysqldump(sprintf("--skip-dump-date --skip-extended-insert --no-tablespaces %s > %s", $this->target_db, $target_file));
107+
}
114108

115-
exec(sprintf("mysqldump --host=%s --port=%u -u'%s' %s %s > %s", $this->mysql->host, $this->mysql->port, $this->mysql->user, $password, $this->target_db, $target_file));
109+
protected function _executePDO($query, $database = null) {
110+
$database = $database ?: $this->target_db;
111+
$connectionString = "mysql:host={$this->mysql->host}:{$this->mysql->port};dbname={$database};charset=utf8mb4";
112+
$pdoDB = new \PDO($connectionString, $this->mysql->user, $this->mysql->password);
113+
$pdoDB->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
116114

117-
if (!file_exists($target_file)) {
118-
throw new \RuntimeException(sprintf('Failed to backup database "%s"!', $this->target_db));
119-
}
115+
return $pdoDB->query($query);
120116
}
121117

122-
protected function _executeSQL($query)
118+
protected function _executeSQL($query, $database = '')
123119
{
124-
$password = empty($this->mysql->password) ? '' : sprintf("--password='%s'", $this->mysql->password);
125-
$cmd = sprintf("echo '$query' | mysql --host=%s --port=%u --user='%s' %s", $this->mysql->host, $this->mysql->port, $this->mysql->user, $password);
120+
return $this->_executeMysqlWithCredentials(function($path) use($query, $database) {
121+
return "echo '$query' | mysql --defaults-extra-file=$path $database";
122+
});
123+
}
126124

127-
return exec($cmd);
125+
protected function _executeMysql($command)
126+
{
127+
return $this->_executeMysqlWithCredentials(function($path) use($command) {
128+
return "mysql --defaults-extra-file=$path $command";
129+
});
130+
}
131+
132+
protected function _executeMysqldump($command)
133+
{
134+
return $this->_executeMysqlWithCredentials(function($path) use($command) {
135+
return "mysqldump --defaults-extra-file=$path $command";
136+
});
137+
}
138+
139+
/**
140+
* Write a temporary --defaults-extra-file file and execute a Mysql command given from the callback
141+
*
142+
* @param callable $callback Receives a single string with the path to the --defaults-extra-file path
143+
* @return void
144+
*/
145+
private function _executeMysqlWithCredentials(callable $callback)
146+
{
147+
try {
148+
$file = tmpfile();
149+
$path = stream_get_meta_data($file)['uri'];
150+
151+
$contents = <<<STR
152+
[client]
153+
user={$this->mysql->user}
154+
password={$this->mysql->password}
155+
host={$this->mysql->host}
156+
port={$this->mysql->port}
157+
STR;
158+
159+
fwrite($file, $contents);
160+
161+
162+
return exec($callback($path));
163+
}
164+
finally {
165+
if (\is_resource($file)) {
166+
\fclose($file);
167+
}
168+
}
128169
}
129170

130171
protected function _promptDatabaseDetails(InputInterface $input, OutputInterface $output)

src/Joomlatools/Console/Command/Database/Drop.php

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
2626
{
2727
parent::execute($input, $output);
2828

29-
$this->check($input, $output);
30-
3129
$result = $this->_executeSQL(sprintf("DROP DATABASE IF EXISTS `%s`", $this->target_db));
3230

3331
if (!empty($result)) {
@@ -36,13 +34,4 @@ protected function execute(InputInterface $input, OutputInterface $output)
3634

3735
return 0;
3836
}
39-
40-
public function check(InputInterface $input, OutputInterface $output)
41-
{
42-
$result = $this->_executeSQL(sprintf("SHOW DATABASES LIKE \"%s\"", $this->target_db));
43-
44-
if (empty($result)) {
45-
throw new \RuntimeException(sprintf('Database %s does not exist', $this->target_db));
46-
}
47-
}
4837
}

src/Joomlatools/Console/Command/Database/Dump.php renamed to src/Joomlatools/Console/Command/Database/Export.php

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020
* @author Steven Rombauts <https://github.com/stevenrombauts>
2121
* @package Joomlatools\Console
2222
*/
23-
class Dump extends AbstractDatabase
23+
class Export extends AbstractDatabase
2424
{
2525
protected function configure()
2626
{
2727
parent::configure();
2828

29-
$this->setName('database:dump')
29+
$this->setName('database:export')
3030
->addOption(
3131
'folder',
3232
null,
@@ -41,7 +41,13 @@ protected function configure()
4141
"File name for the backup. Defaults to sitename_date.format",
4242
null
4343
)
44-
->setDescription('Dump the database of a site');
44+
->addOption(
45+
'per-table',
46+
null,
47+
InputOption::VALUE_NONE,
48+
"If set, each table will be exported into a separate file",
49+
)
50+
->setDescription('Export the database of a site');
4551
}
4652

4753
protected function execute(InputInterface $input, OutputInterface $output)
@@ -50,10 +56,30 @@ protected function execute(InputInterface $input, OutputInterface $output)
5056

5157
$this->check();
5258

53-
$path = $input->getOption('folder') ?? $this->target_dir;
54-
$path .= '/'.($input->getOption('filename') ?? $this->site.'_database_'.date('Y-m-d').'.sql');
59+
$folder = $input->getOption('folder') ?? $this->target_dir;
60+
61+
if (!\is_dir($folder)) {
62+
@mkdir($folder, 0755, true);
63+
64+
if (!\is_dir($folder)) {
65+
throw new \RuntimeException("Folder $folder doesn't exist.");
66+
}
67+
}
68+
69+
if ($input->getOption('per-table'))
70+
{
71+
$statement = $this->_executePDO('show tables');
5572

56-
$this->_backupDatabase($path);
73+
while (($table = $statement->fetchColumn()) !== false) {
74+
75+
$this->_executeMysqldump(sprintf("--skip-dump-date --skip-comments --skip-extended-insert --no-tablespaces %s %s > %s", $this->target_db, $table, $folder.'/'.$table.'.sql'));
76+
}
77+
78+
} else {
79+
$path = $folder.'/'.($input->getOption('filename') ?? $this->site.'_database_'.date('Y-m-d').'.sql');
80+
81+
$this->_backupDatabase($path);
82+
}
5783

5884
return 0;
5985
}
@@ -63,5 +89,12 @@ public function check()
6389
if (!file_exists($this->target_dir)) {
6490
throw new \RuntimeException(sprintf('The site %s does not exist', $this->site));
6591
}
92+
93+
$result = $this->_executeSQL(sprintf("SHOW DATABASES LIKE \"%s\"", $this->target_db));
94+
95+
if (empty($result)) {
96+
throw new \RuntimeException(sprintf('Database %s does not exist', $this->target_db));
97+
}
98+
6699
}
67100
}

src/Joomlatools/Console/Command/Database/Install.php

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
8888
{
8989
parent::execute($input, $output);
9090

91-
$password = empty($this->mysql->password) ? '' : sprintf("-p'%s'", $this->mysql->password);
92-
9391
$this->drop = $input->getOption('drop');
9492
$this->skip_check = $input->getOption('skip-exists-check');
9593
$this->skip_create_statement = $input->getOption('skip-create-statement');
@@ -119,7 +117,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
119117

120118
file_put_contents($tmp, $contents);
121119

122-
$result = exec(sprintf("mysql --host=%s --port=%u --user='%s' %s %s < %s", $this->mysql->host, $this->mysql->port, $this->mysql->user, $password, $this->target_db, $tmp));
120+
$result = $this->_executeMysql(sprintf("%s < %s", $this->target_db, $tmp));
123121

124122
unlink($tmp);
125123

@@ -143,10 +141,8 @@ protected function execute(InputInterface $input, OutputInterface $output)
143141

144142
$version = Util::getJoomlaVersion($this->target_dir);
145143

146-
$executeQuery = function ($sql) use ($password) {
147-
$command = sprintf("mysql --host=%s --port=%u --user='%s' %s %s -e %s", $this->mysql->host, $this->mysql->port, $this->mysql->user, $password, $this->target_db, escapeshellarg($sql));
148-
149-
exec ($command);
144+
$executeQuery = function($sql) {
145+
$this->_executeMysql(sprintf("%s -e %s", $this->target_db, escapeshellarg($sql)));
150146
};
151147

152148
$executeQuery("REPLACE INTO j_schemas (extension_id, version_id) VALUES (700, '$schema');");

src/Joomlatools/Console/Command/Site/Create.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
192192
'--www' => $this->www
193193
);
194194

195-
$optionalArgs = array('sample-data', 'symlink', 'projects-dir', 'interactive', 'mysql-login', 'mysql_db_prefix', 'mysql-db-prefix', 'mysql-host', 'mysql-port', 'mysql-database', 'options', 'skip-create-statement', 'use-webroot-dir');
195+
$optionalArgs = array('sample-data', 'symlink', 'projects-dir', 'interactive', 'mysql-login', 'mysql-db-prefix', 'mysql-host', 'mysql-port', 'mysql-database', 'options', 'skip-create-statement', 'use-webroot-dir');
196196
foreach ($optionalArgs as $optionalArg)
197197
{
198198
$value = $input->getOption($optionalArg);

src/Joomlatools/Console/Command/Site/Delete.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,6 @@ public function check(InputInterface $input, OutputInterface $output)
5656
if (getcwd() === $this->target_dir && getcwd() !== $this->www) {
5757
throw new \RuntimeException('You are currently in the directory you are trying to delete. Aborting');
5858
}
59-
60-
if (!is_dir($this->target_dir)) {
61-
throw new \RuntimeException(sprintf('The site %s does not exist!', $this->site));
62-
}
6359
}
6460

6561
public function deleteDirectory(InputInterface $input, OutputInterface $output)
@@ -78,7 +74,7 @@ public function deleteDatabase(InputInterface $input, OutputInterface $output)
7874
'site' => $this->site
7975
);
8076

81-
$optionalArgs = array('mysql-login', 'mysql_db_prefix', 'mysql-db-prefix', 'mysql-host', 'mysql-port', 'mysql-database');
77+
$optionalArgs = array('mysql-login', 'mysql-db-prefix', 'mysql-host', 'mysql-port', 'mysql-database');
8278
foreach ($optionalArgs as $optionalArg)
8379
{
8480
$value = $input->getOption($optionalArg);

src/Joomlatools/Console/Command/Site/Install.php

Lines changed: 5 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414

1515
use Joomlatools\Console\Command;
1616
use Joomlatools\Console\Command\Database;
17-
use Joomlatools\Console\Command\Vhost;
18-
use Joomlatools\Console\Joomla\Util;
1917

2018
class Install extends Database\AbstractDatabase
2119
{
@@ -115,11 +113,11 @@ protected function execute(InputInterface $input, OutputInterface $output)
115113
$this->installExtensions($input, $output);
116114
}
117115

118-
$this->_enableWebInstaller($input, $output);
119-
120-
$output->writeln("Your new Joomla site has been configured.");
116+
$output->writeln("Your new Joomla site has been created.");
117+
$output->writeln("It was installed using the domain name <info>$this->site.test</info>.");
121118
$output->writeln("You can login using the following username and password combination: <info>admin</info>/<info>admin</info>.");
122119

120+
123121
return 0;
124122
}
125123

@@ -138,7 +136,7 @@ public function importdb(InputInterface $input, OutputInterface $output)
138136
'--www' => $this->www
139137
);
140138

141-
$optionalArgs = array('sample-data', 'drop', 'mysql-login', 'mysql_db_prefix', 'mysql-db-prefix', 'mysql-host', 'mysql-port', 'mysql-database', 'skip-exists-check', 'skip-create-statement', 'www', 'use-webroot-dir');
139+
$optionalArgs = array('sample-data', 'drop', 'mysql-login', 'mysql-db-prefix', 'mysql-host', 'mysql-port', 'mysql-database', 'skip-exists-check', 'skip-create-statement', 'www', 'use-webroot-dir');
142140
foreach ($optionalArgs as $optionalArg)
143141
{
144142
$value = $input->getOption($optionalArg);
@@ -163,7 +161,7 @@ public function createConfig(InputInterface $input, OutputInterface $output)
163161
'--www' => $this->www
164162
);
165163

166-
$optionalArgs = array('overwrite', 'mysql-login', 'mysql_db_prefix', 'mysql-db-prefix', 'mysql-host', 'mysql-port', 'mysql-database', 'mysql-driver', 'interactive', 'options', 'www', 'use-webroot-dir');
164+
$optionalArgs = array('overwrite', 'mysql-login', 'mysql-db-prefix', 'mysql-host', 'mysql-port', 'mysql-database', 'mysql-driver', 'interactive', 'options', 'www', 'use-webroot-dir');
167165
foreach ($optionalArgs as $optionalArg)
168166
{
169167
$value = $input->getOption($optionalArg);
@@ -204,55 +202,4 @@ public function installExtensions(InputInterface $input, OutputInterface $output
204202

205203
$installer->run($extension_input, $output);
206204
}
207-
208-
protected function _enableWebInstaller(InputInterface $input, OutputInterface $output)
209-
{
210-
$version = Util::getJoomlaVersion($this->target_dir);
211-
212-
if (version_compare($version->release, '3.2.0', '<')) {
213-
return;
214-
}
215-
216-
$xml = simplexml_load_file('http://appscdn.joomla.org/webapps/jedapps/webinstaller.xml');
217-
218-
if(!$xml)
219-
{
220-
$output->writeln('<warning>Failed to install web installer</warning>');
221-
222-
return;
223-
}
224-
225-
$url = '';
226-
foreach($xml->update->downloads->children() as $download)
227-
{
228-
$attributes = $download->attributes();
229-
if($attributes->type == 'full' && $attributes->format == 'zip')
230-
{
231-
$url = (string) $download;
232-
break;
233-
}
234-
}
235-
236-
if(empty($url)) {
237-
return;
238-
}
239-
240-
$filename = Util::getWritablePath().'/cache/'.basename($url);
241-
if(!file_exists($filename))
242-
{
243-
$bytes = file_put_contents($filename, fopen($url, 'r'));
244-
if($bytes === false || $bytes == 0) {
245-
return;
246-
}
247-
}
248-
249-
`mkdir -p $this->target_dir/plugins/installer`;
250-
`cd $this->target_dir/plugins/installer/ && unzip -o $filename`;
251-
252-
$sql = "INSERT INTO `j_extensions` (`name`, `type`, `element`, `folder`, `enabled`, `access`, `manifest_cache`) VALUES ('plg_installer_webinstaller', 'plugin', 'webinstaller', 'installer', 1, 1, '{\"name\":\"plg_installer_webinstaller\",\"type\":\"plugin\",\"version\":\"".$xml->update->version."\",\"description\":\"Web Installer\"}');";
253-
$sql = escapeshellarg($sql);
254-
255-
$password = empty($this->mysql->password) ? '' : sprintf("-p'%s'", $this->mysql->password);
256-
exec(sprintf("mysql --host=%s --port=%u -u'%s' %s %s -e %s", $this->mysql->host, $this->mysql->port, $this->mysql->user, $password, $this->target_db, $sql));
257-
}
258205
}

src/Joomlatools/Console/Command/Vhost/Remove.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77

88
namespace Joomlatools\Console\Command\Vhost;
99

10-
use Joomlatools\Console\Command;
11-
use Symfony\Component\Console\Input\InputArgument;
1210
use Symfony\Component\Console\Input\InputInterface;
1311
use Symfony\Component\Console\Input\InputOption;
1412
use Symfony\Component\Console\Output\OutputInterface;
@@ -49,10 +47,6 @@ protected function execute(InputInterface $input, OutputInterface $output)
4947
{
5048
parent::execute($input, $output);
5149

52-
if (!file_exists($this->target_dir)) {
53-
throw new \RuntimeException(sprintf('Site not found: %s', $this->site));
54-
}
55-
5650
$file = $this->_getVhostPath($input);
5751

5852
if (is_file($file))

0 commit comments

Comments
 (0)