diff --git a/app/Models/BatchData.php b/app/Models/BatchData.php index 036e9f43..21e20408 100644 --- a/app/Models/BatchData.php +++ b/app/Models/BatchData.php @@ -2,34 +2,64 @@ namespace App\Models; -use Override; use Exception; use Filament\Facades\Filament; +use Illuminate\Support\Facades\Log; -class BatchData extends \FamilyTree365\LaravelGedcom\Utils\BatchData +/** + * Application-level BatchData helper. + * + * The vendor's FamilyTree365\LaravelGedcom\Utils\BatchData is declared final + * and therefore cannot be extended. This class replicates the upsert logic + * from the vendor while injecting the current tenant's team_id so that all + * imported records are scoped to the right team. + */ +class BatchData { - #[Override] - public static function upsert($modelClass, $conn, array $values, array $uniqueBy, array $update = []) + private const int DEFAULT_CHUNK_SIZE = 1000; + + public static function upsert(string $modelClass, string $conn, array $values, array $uniqueBy, array $update = []): bool { - // error_log("modi upsert"); + if (empty($values)) { + return true; + } + $teamId = null; - // Only try to get tenant if we're in a web context with auth and Filament is properly initialized + // Only try to get tenant in a web context where auth and Filament are available if (auth()->check() && app()->bound('filament') && Filament::hasTenancy()) { try { $tenant = Filament::getTenant(); - $teamId = $tenant ? $tenant->id : null; - } catch (Exception $e) { - // Silently handle cases where tenant context is not available - $teamId = null; + $teamId = $tenant?->id; + } catch (Exception) { + // Silently fall back when tenant context is unavailable (e.g. queue worker) } } - // Add team_id to each data item + // Inject team_id into every record so imports land in the correct team foreach ($values as &$value) { $value['team_id'] = $teamId; } + unset($value); + + $chunks = array_chunk($values, self::DEFAULT_CHUNK_SIZE); + $success = true; + + foreach ($chunks as $chunk) { + try { + $result = app($modelClass)->on($conn)->upsert($chunk, $uniqueBy, $update); + $success = $success && ($result !== false); + } catch (\Throwable $e) { + Log::error('BatchData::upsert chunk failed', [ + 'model' => $modelClass, + 'connection' => $conn, + 'chunk_size' => count($chunk), + 'error' => $e->getMessage(), + ]); + $success = false; + } + } - return parent::upsert($modelClass, $conn, $values, $uniqueBy, $update); + return $success; } } diff --git a/composer.json b/composer.json index cb5cbc72..47a0ef36 100644 --- a/composer.json +++ b/composer.json @@ -10,6 +10,7 @@ "license": "MIT", "require": { "php": "^8.3", + "cweagans/composer-patches": "^1.7", "bezhansalleh/filament-shield": "^4.0", "filament/filament": "^5.1", "filament/spatie-laravel-settings-plugin": "^5.0", @@ -77,6 +78,14 @@ "dont-discover": [ "liberu-genealogy/laravel-gedcom" ] + }, + "patches": { + "liberu-genealogy/laravel-gedcom": { + "Fix ParentData uid empty string (use ?: instead of ??)": "patches/liberu-genealogy/laravel-gedcom/fix-parent-data-uid-empty-string.patch", + "Fix Even.php variable name collision (eventData)": "patches/liberu-genealogy/laravel-gedcom/fix-even-variable-collision.patch", + "Fix FamilyData husband/wife lookup by gid": "patches/liberu-genealogy/laravel-gedcom/fix-family-data-gid-lookup.patch", + "Fix Fam/Even.php array::class TypeError on non-object events": "patches/liberu-genealogy/laravel-gedcom/fix-fam-even-array-class-error.patch" + } } }, "config": { @@ -84,6 +93,7 @@ "preferred-install": "dist", "sort-packages": true, "allow-plugins": { + "cweagans/composer-patches": true, "pestphp/pest-plugin": true, "php-http/discovery": true } diff --git a/patches/liberu-genealogy/laravel-gedcom/fix-even-variable-collision.patch b/patches/liberu-genealogy/laravel-gedcom/fix-even-variable-collision.patch new file mode 100644 index 00000000..34186689 --- /dev/null +++ b/patches/liberu-genealogy/laravel-gedcom/fix-even-variable-collision.patch @@ -0,0 +1,21 @@ +--- a/src/Utils/Importer/Indi/Even.php ++++ b/src/Utils/Importer/Indi/Even.php +@@ -89,11 +89,11 @@ class Even + $caus = $even->getCaus(); + $age = $even->getAge(); + $agnc = $even->getAgnc(); + + // Extract event-specific family context data +- $eventData = self::extractEventSpecificData($even, $class_name); +- $adop = $eventData['adop']; +- $adop_famc = $eventData['adop_famc']; +- $birt_famc = $eventData['birt_famc']; +- $chr_famc = $eventData['chr_famc']; ++ $specificEventData = self::extractEventSpecificData($even, $class_name); ++ $adop = $specificEventData['adop']; ++ $adop_famc = $specificEventData['adop_famc']; ++ $birt_famc = $specificEventData['birt_famc']; ++ $chr_famc = $specificEventData['chr_famc']; + + // store Even + $key = [ diff --git a/patches/liberu-genealogy/laravel-gedcom/fix-fam-even-array-class-error.patch b/patches/liberu-genealogy/laravel-gedcom/fix-fam-even-array-class-error.patch new file mode 100644 index 00000000..23345d06 --- /dev/null +++ b/patches/liberu-genealogy/laravel-gedcom/fix-fam-even-array-class-error.patch @@ -0,0 +1,11 @@ +--- a/src/Utils/Importer/Fam/Even.php ++++ b/src/Utils/Importer/Fam/Even.php +@@ -18,7 +18,7 @@ class Even + public static function read($conn, $even, $fam, $obje_ids = []) + { + try { +- if ($even == null || $fam === null) { ++ if ($even == null || !is_object($even) || $fam === null) { + return; + } + $class_name = $even::class; diff --git a/patches/liberu-genealogy/laravel-gedcom/fix-family-data-gid-lookup.patch b/patches/liberu-genealogy/laravel-gedcom/fix-family-data-gid-lookup.patch new file mode 100644 index 00000000..9545b477 --- /dev/null +++ b/patches/liberu-genealogy/laravel-gedcom/fix-family-data-gid-lookup.patch @@ -0,0 +1,31 @@ +--- a/src/Utils/FamilyData.php ++++ b/src/Utils/FamilyData.php +@@ -54,23 +54,16 @@ class FamilyData + foreach ($children as $child) { + if (!isset($persons_id[$child])) { +- $persons_id[$child] = app(Person::class)->where('gid', $child)->first()->id; ++ $persons_id[$child] = app(Person::class)->where('gid', $child)->first()?->id; + } + } + +- $husband_key = $parentData ? array_search($husb, array_column($parentData, 'gid')) : null; +- $husband_uid = $parentData[$husband_key]['uid'] ?? null; +- $husband = $husband_uid ? app(Person::class)->where('uid', $husband_uid)->first() : null; +- $husband_id = $husband?->id; +- +- $wife_key = $parentData ? array_search($wife, array_column($parentData, 'gid')) : null; +- $wife_uid = $parentData[$wife_key]['uid'] ?? null; +- $wife = $wife_uid ? app(Person::class)->where('uid', $wife_uid)->first() : null; +- $wife_id = $wife?->id; ++ $husband_id = $husb ? app(Person::class)->where('gid', $husb)->first()?->id : null; ++ $wife_id = $wife ? app(Person::class)->where('gid', $wife)->first()?->id : null; + + $persons_id[$husb] = $husband_id; + $persons_id[$wife] = $wife_id; +@@ -86,7 +79,7 @@ class FamilyData + otherFamRecord::insertFamilyData($conn, $persons_id, $families, $obje_ids, $sour_ids); +- } catch (\Exception $e) { ++ } catch (\Throwable $e) { + $error = $e->getMessage(); + + return \Log::error($error); diff --git a/patches/liberu-genealogy/laravel-gedcom/fix-parent-data-uid-empty-string.patch b/patches/liberu-genealogy/laravel-gedcom/fix-parent-data-uid-empty-string.patch new file mode 100644 index 00000000..28b33fb9 --- /dev/null +++ b/patches/liberu-genealogy/laravel-gedcom/fix-parent-data-uid-empty-string.patch @@ -0,0 +1,11 @@ +--- a/src/Utils/ParentData.php ++++ b/src/Utils/ParentData.php +@@ -82,7 +82,7 @@ class ParentData + // added to database + // string value + $sex = preg_replace('/[^MF]/', '', (string) $individual->getSex()); +- $uid = $individual->getUid() ?? strtoupper(str_replace('-', '', (string) Str::uuid())); ++ $uid = $individual->getUid() ?: strtoupper(str_replace('-', '', (string) Str::uuid())); + $resn = $individual->getResn(); + $rin = $individual->getRin(); + $rfn = $individual->getRfn();