summaryrefslogtreecommitdiff
path: root/app/Cli
diff options
context:
space:
mode:
authorGreg Roach <greg@subaqua.co.uk>2025-05-13 11:28:56 +0100
committerGreg Roach <greg@subaqua.co.uk>2025-05-13 11:28:56 +0100
commit1fe5972b9c911ca4873c4a0fb40a416598b02997 (patch)
tree458ee27696873af036b8266f0877ff83bf7eb7df /app/Cli
parent036af8696129956af9534bd1e19e74a9d2305337 (diff)
downloadwebtrees-1fe5972b9c911ca4873c4a0fb40a416598b02997.tar.gz
webtrees-1fe5972b9c911ca4873c4a0fb40a416598b02997.tar.bz2
webtrees-1fe5972b9c911ca4873c4a0fb40a416598b02997.zip
Add CLI for tree-export
Diffstat (limited to 'app/Cli')
-rw-r--r--app/Cli/Commands/TreeExport.php115
-rw-r--r--app/Cli/Console.php2
2 files changed, 101 insertions, 16 deletions
diff --git a/app/Cli/Commands/TreeExport.php b/app/Cli/Commands/TreeExport.php
index b058e9adcd..493178c7e7 100644
--- a/app/Cli/Commands/TreeExport.php
+++ b/app/Cli/Commands/TreeExport.php
@@ -21,7 +21,6 @@ namespace Fisharebest\Webtrees\Cli\Commands;
use Fisharebest\Webtrees\Auth;
use Fisharebest\Webtrees\DB;
-use Fisharebest\Webtrees\Encodings\UTF8;
use Fisharebest\Webtrees\Services\GedcomExportService;
use Fisharebest\Webtrees\Services\TreeService;
use Symfony\Component\Console\Completion\CompletionInput;
@@ -30,12 +29,21 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
+use ZipArchive;
use function addcslashes;
+use function filesize;
use function stream_get_contents;
final class TreeExport extends AbstractCommand
{
+ private const array ACCESS_LEVELS = [
+ 'none' => Auth::PRIV_HIDE,
+ 'manager' => Auth::PRIV_NONE,
+ 'member' => Auth::PRIV_USER,
+ 'visitor' => Auth::PRIV_PRIVATE,
+ ];
+
public function __construct(
private readonly GedcomExportService $gedcom_export_service,
private readonly TreeService $tree_service,
@@ -48,8 +56,8 @@ final class TreeExport extends AbstractCommand
$this
->setName(name: 'tree-export')
->addArgument(name: 'tree_name', mode: InputArgument::REQUIRED, description: 'The name of the tree', suggestedValues: self::autoCompleteTreeName(...))
- ->addOption(name: 'format', shortcut: null, mode: InputOption::VALUE_REQUIRED, description: 'Export format')
- ->addOption(name: 'filename', shortcut: null, mode: InputOption::VALUE_REQUIRED, description: 'Export filename')
+ ->addOption(name: 'format', mode: InputOption::VALUE_REQUIRED, description: 'Export format: gedcom (default), gedzip, zip or zipmedia')
+ ->addOption(name: 'privacy', mode: InputOption::VALUE_REQUIRED, description: 'Apply privacy: none (default), manager, member or visitor')
->setDescription(description: 'Export a tree to a GEDCOM file');
}
@@ -68,9 +76,25 @@ final class TreeExport extends AbstractCommand
{
$io = new SymfonyStyle(input: $input, output: $output);
- $tree_name = $input->getArgument(name: 'tree_name');
+ $tree_name = $this->stringArgument(input: $input, name: 'tree_name');
$format = $this->stringOption(input: $input, name: 'format');
- $filename = $this->stringOption(input: $input, name: 'filename');
+ $privacy = $this->stringOption(input: $input, name: 'privacy');
+
+ if ($format === '') {
+ $format = 'gedcom';
+ }
+
+ if ($privacy === '') {
+ $privacy = 'none';
+ }
+
+ $access_level = self::ACCESS_LEVELS[$privacy] ?? null;
+
+ if ($access_level === null) {
+ $io->error(message: 'privacy option should be none, manager, member or visitor');
+
+ return self::FAILURE;
+ }
$tree = $this->tree_service->all()[$tree_name] ?? null;
@@ -80,20 +104,81 @@ final class TreeExport extends AbstractCommand
return self::FAILURE;
}
- $stream = $this->gedcom_export_service->export(
+ $start_time = microtime(true);
+
+ switch ($format) {
+ case 'gedcom':
+ $media_path = null;
+ $filename = $tree_name . '.ged';
+ $zip_filesystem = null;
+ break;
+
+ case 'gedzip':
+ $media_path = '';
+ $filename = $tree_name . '.gdz';
+ $zip_filesystem = new ZipArchive();
+ $zip_filesystem->open($filename, ZipArchive::CREATE | ZipArchive::OVERWRITE);
+ break;
+
+ case 'zip':
+ $media_path = null;
+ $filename = $tree_name . '.zip';
+ $zip_filesystem = new ZipArchive();
+ $zip_filesystem->open($filename, ZipArchive::CREATE | ZipArchive::OVERWRITE);
+ break;
+
+ case 'zipmedia':
+ $media_path = $tree->getPreference('MEDIA_DIRECTORY');
+ $filename = $tree_name . '.zip';
+ $zip_filesystem = new ZipArchive();
+ $zip_filesystem->open($filename, ZipArchive::CREATE | ZipArchive::OVERWRITE);
+ break;
+
+ default:
+ $io->error(message: 'Format option should be gedcom, gedzip, zip or zipmedia');
+
+ return self::FAILURE;
+ }
+
+ $resource = $this->gedcom_export_service->export(
tree: $tree,
- sort_by_xref: false,
- encoding: UTF8::NAME,
- access_level: Auth::PRIV_HIDE,
- line_endings: 'CRLF',
- records: null,
- zip_filesystem: null,
- media_path: null,
+ sort_by_xref: true,
+ access_level: $access_level,
+ zip_filesystem: $zip_filesystem,
+ media_path: $media_path,
);
- echo stream_get_contents($stream);
+ $gedcom = stream_get_contents($resource);
+ fclose($resource);
+
+ if ($gedcom === false) {
+ $io->error(message: 'Failed to read GEDCOM');
+
+ return self::FAILURE;
+ }
+
+ switch ($format) {
+ case 'gedcom':
+ file_put_contents($filename, $gedcom);
+ break;
+
+ case 'gedzip':
+ $zip_filesystem->addFromString('gedcom.ged', $gedcom);
+ $zip_filesystem->close();
+ break;
+
+ case 'zip':
+ case 'zipmedia':
+ $zip_filesystem->addFromString($tree_name . '.ged', $gedcom);
+ $zip_filesystem->close();
+ break;
+ }
+
+ $bytes = filesize($filename);
+ $seconds = microtime(true) - $start_time;
+ $message = sprintf('File exported successfully. %d bytes written to %s in %.3f seconds', $bytes, $filename, $seconds);
- $io->success('File exported successfully.');
+ $io->success($message);
return self::SUCCESS;
}
diff --git a/app/Cli/Console.php b/app/Cli/Console.php
index 4ddff02d9a..f3bf5def29 100644
--- a/app/Cli/Console.php
+++ b/app/Cli/Console.php
@@ -37,7 +37,7 @@ final class Console extends Application
Commands\SiteOnline::class,
Commands\SiteSetting::class,
//Commands\TreeCreate::class,
- //Commands\TreeExport::class,
+ Commands\TreeExport::class,
Commands\TreeList::class,
Commands\TreeSetting::class,
//Commands\UserCreate::class,