Skip to content

Commit 9a6221d

Browse files
author
Marc Geurts
committed
GEDCOM Import: Add importing media files from ZIP
1 parent 902c61d commit 9a6221d

File tree

6 files changed

+675
-48
lines changed

6 files changed

+675
-48
lines changed

app/Gedcom/Import/Import.php

Lines changed: 130 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
/**
1717
* Main GEDCOM Import orchestrator class
18+
* Supports both .ged files and .zip files with media
1819
*/
1920
final class Import implements CreatesTeams
2021
{
@@ -30,6 +31,8 @@ final class Import implements CreatesTeams
3031

3132
private CoupleCreator $coupleCreator;
3233

34+
private ?MediaImportHandler $mediaHandler = null;
35+
3336
/**
3437
* Initialize with user and create a new team
3538
*/
@@ -48,55 +51,167 @@ public function __construct(?string $teamName, ?string $teamDescription)
4851
}
4952

5053
/**
51-
* Import GEDCOM file content
54+
* Import GEDCOM file content (text only)
55+
*
56+
* @param string $gedcomContent Raw GEDCOM text content
57+
* @return array Import results
5258
*/
5359
public function import(string $gedcomContent): array
5460
{
55-
// At the start of your import method, increase time and memory limits
61+
return $this->processImport($gedcomContent, []);
62+
}
63+
64+
/**
65+
* Import GEDCOM from ZIP file (with media)
66+
*
67+
* @param string $zipPath Path to ZIP file
68+
* @return array Import results
69+
*/
70+
public function importFromZip(string $zipPath): array
71+
{
72+
$zipImporter = new ZipImporter();
73+
74+
try {
75+
// Extract ZIP file
76+
Log::info('Extracting ZIP file', ['path' => $zipPath]);
77+
$zipImporter->extract($zipPath);
78+
79+
$gedcomContent = $zipImporter->getGedcomContent();
80+
$mediaFiles = $zipImporter->getMediaFiles();
81+
82+
Log::info('ZIP extracted successfully', [
83+
'media_files' => count($mediaFiles),
84+
'gedcom_size' => mb_strlen($gedcomContent),
85+
]);
86+
87+
// Process import with media files
88+
return $this->processImport($gedcomContent, $mediaFiles);
89+
} catch (Exception $e) {
90+
Log::error('ZIP import failed', [
91+
'error' => $e->getMessage(),
92+
'trace' => $e->getTraceAsString(),
93+
]);
94+
95+
return [
96+
'success' => false,
97+
'error' => 'ZIP extraction failed: ' . $e->getMessage(),
98+
];
99+
} finally {
100+
$zipImporter->cleanup();
101+
}
102+
}
103+
104+
/**
105+
* Get import statistics
106+
*/
107+
public function getStatistics(): array
108+
{
109+
$parsedData = $this->parser->getParsedData();
110+
111+
$stats = [
112+
'individuals_parsed' => $parsedData ? count($parsedData->getIndividuals()) : 0,
113+
'families_parsed' => $parsedData ? count($parsedData->getFamilies()) : 0,
114+
'individuals_imported' => count($this->individualImporter->getPersonMap()),
115+
'families_imported' => count($this->familyImporter->getFamilyMap()),
116+
];
117+
118+
if ($this->mediaHandler) {
119+
$stats['media_references'] = count($this->mediaHandler->getPersonMediaMap());
120+
}
121+
122+
return $stats;
123+
}
124+
125+
/**
126+
* Core import processing logic
127+
*
128+
* @param string $gedcomContent GEDCOM text content
129+
* @param array $mediaFiles Array of basename => filepath for media
130+
* @return array Import results
131+
*/
132+
private function processImport(string $gedcomContent, array $mediaFiles): array
133+
{
134+
// Increase limits for large imports
56135
ini_set('max_execution_time', 300); // 5 minutes
57136
ini_set('memory_limit', '512M');
58137

59138
try {
60139
DB::beginTransaction();
61140

141+
// Initialize media handler if we have media files
142+
if (! empty($mediaFiles)) {
143+
$this->mediaHandler = new MediaImportHandler($mediaFiles);
144+
145+
// Parse media objects from GEDCOM content BEFORE parsing individuals
146+
$this->mediaHandler->parseMediaObjects($gedcomContent);
147+
148+
Log::info('Media handler initialized', [
149+
'files_count' => count($mediaFiles),
150+
'media_objects_count' => count($this->mediaHandler->getMediaObjects()),
151+
]);
152+
}
153+
62154
// Parse GEDCOM content
63155
$parsedData = $this->parser->parse($gedcomContent);
64156

65-
Log::info('GEDCOM IMPORT: parseGedcom', ['gedcomData' => $parsedData->getGedcomData()]);
157+
Log::info('GEDCOM parsed', [
158+
'individuals' => count($parsedData->getIndividuals()),
159+
'families' => count($parsedData->getFamilies()),
160+
]);
66161

67162
// Import individuals first
68-
$personMap = $this->individualImporter->import($parsedData->getIndividuals());
163+
$personMap = $this->individualImporter->import(
164+
$parsedData->getIndividuals(),
165+
$this->mediaHandler
166+
);
69167

70-
Log::info('GEDCOM IMPORT: importIndividuals', [
71-
'individuals' => $parsedData->getIndividuals(),
72-
'personMap' => $personMap,
168+
Log::info('Individuals imported', [
169+
'count' => count($personMap),
73170
]);
74171

75172
// Import families and relationships
76-
$familyMap = $this->familyImporter->import($parsedData->getFamilies(), $personMap);
173+
$familyMap = $this->familyImporter->import(
174+
$parsedData->getFamilies(),
175+
$personMap
176+
);
77177

78-
Log::info('GEDCOM IMPORT: importFamilies', [
79-
'families' => $parsedData->getFamilies(),
80-
'familyMap' => $familyMap,
178+
Log::info('Families imported', [
179+
'count' => count($familyMap),
81180
]);
82181

83182
// Create couples from families
84183
$this->coupleCreator->create($familyMap, $personMap);
85184

86-
Log::info('GEDCOM IMPORT: createCouples', ['data' => '????']);
185+
Log::info('Couples created');
186+
187+
// Import media files if available
188+
$mediaStats = null;
189+
if ($this->mediaHandler) {
190+
Log::info('Starting media import');
191+
$mediaStats = $this->mediaHandler->importMediaToPersons($personMap);
192+
Log::info('Media import complete', $mediaStats);
193+
}
87194

88195
DB::commit();
89196

90-
return [
197+
$result = [
91198
'success' => true,
92199
'team' => $this->team->name,
93200
'individuals_imported' => count($personMap),
94201
'families_imported' => count($familyMap),
95202
'message' => 'GEDCOM file imported successfully',
96203
];
204+
205+
if ($mediaStats) {
206+
$result['media_stats'] = $mediaStats;
207+
}
208+
209+
return $result;
97210
} catch (Exception $e) {
98211
DB::rollBack();
99-
Log::error('GEDCOM Import Error: ' . $e->getMessage(), ['trace' => $e->getTraceAsString()]);
212+
Log::error('GEDCOM Import Error: ' . $e->getMessage(), [
213+
'trace' => $e->getTraceAsString(),
214+
]);
100215

101216
return [
102217
'success' => false,
@@ -105,22 +220,6 @@ public function import(string $gedcomContent): array
105220
}
106221
}
107222

108-
/**
109-
* Get import statistics
110-
*/
111-
public function getStatistics(): array
112-
{
113-
// Only get parsed data if parsing has been done
114-
$parsedData = $this->parser->getParsedData();
115-
116-
return [
117-
'individuals_parsed' => $parsedData ? count($parsedData->getIndividuals()) : 0,
118-
'families_parsed' => $parsedData ? count($parsedData->getFamilies()) : 0,
119-
'individuals_imported' => count($this->individualImporter->getPersonMap()),
120-
'families_imported' => count($this->familyImporter->getFamilyMap()),
121-
];
122-
}
123-
124223
/**
125224
* Create a new team for the import
126225
*/
@@ -134,13 +233,10 @@ private function createTeam(string $name, ?string $description): Team
134233
'personal_team' => false,
135234
]));
136235

137-
// -----------------------------------------------------------------------
138-
// create team photo folder
139-
// -----------------------------------------------------------------------
236+
// Create team photo folder
140237
if (! Storage::disk('photos')->exists($team->id)) {
141238
Storage::disk('photos')->makeDirectory($team->id);
142239
}
143-
// -----------------------------------------------------------------------
144240

145241
return $team;
146242
}

app/Gedcom/Import/IndividualImporter.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,23 @@ public function __construct(Team $team)
2727

2828
/**
2929
* Import individuals from parsed GEDCOM data
30+
*
31+
* @param array $individuals Parsed individual records
32+
* @param MediaImportHandler|null $mediaHandler Optional media handler for extracting references
33+
* @return array Mapping of GEDCOM ID to Person database ID
3034
*/
31-
public function import(array $individuals): array
35+
public function import(array $individuals, ?MediaImportHandler $mediaHandler = null): array
3236
{
3337
foreach ($individuals as $gedcomId => $individual) {
3438
if ($individual === null) {
3539
continue;
3640
}
3741

42+
// Extract media references if handler is provided
43+
if ($mediaHandler) {
44+
$mediaHandler->extractMediaReferences($gedcomId, $individual);
45+
}
46+
3847
$personData = $this->extractPersonData($individual);
3948

4049
// Truncate fields to prevent database errors
@@ -250,6 +259,9 @@ private function extractPersonData(?array $individual): array
250259
}
251260
$data['metadata']['education'] = $education;
252261
break;
262+
263+
// Note: OBJE tags are handled by MediaImportHandler
264+
// We skip them here to avoid duplication
253265
}
254266

255267
// Handle nickname from NAME variations

0 commit comments

Comments
 (0)