legacy: --since-Delta für legacy:import + Importer setzen Timestamps wieder korrekt
--since=<Zeitpunkt> schränkt den Quell-Scan auf Legacy-Zeilen ein, deren created_at ODER updated_at im Fenster liegt (users/companies/contacts/ press-releases; Kategorien und link-associations bleiben ungefiltert). Kombiniert mit --force werden geänderte Bestandszeilen aktualisiert — damit dauert ein Tages-Delta Sekunden statt eines Volldurchlaufs über 150k+ Zeilen. Dazu Bugfix, der den Delta erst rund macht: User-/Company-/Contact- Importer übergaben created_at/updated_at innerhalb von updateOrCreate — die Felder sind nicht fillable und wurden stillschweigend verworfen (Live-Befund: NULL-Timestamps, bisher nur durch legacy:fix-timestamps geheilt). Jetzt explizit per forceFill wie im PressReleaseImporter. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
22b7bd38b7
commit
a0c2e663dc
8 changed files with 136 additions and 11 deletions
|
|
@ -43,6 +43,10 @@ class CompanyImporter
|
|||
|
||||
DB::connection($conn)
|
||||
->table('company')
|
||||
->when($ctx->since, fn ($query) => $query->where(function ($window) use ($ctx): void {
|
||||
$window->where('created_at', '>=', $ctx->since)
|
||||
->orWhere('updated_at', '>=', $ctx->since);
|
||||
}))
|
||||
->orderBy('id')
|
||||
->chunk(self::CHUNK_SIZE, function ($rows) use ($ctx, $result, $legacyPortal, $portal, $responsibles, $members): void {
|
||||
foreach ($rows as $row) {
|
||||
|
|
@ -117,12 +121,17 @@ class CompanyImporter
|
|||
'logo_path' => $row->logo ?: null,
|
||||
'is_active' => (bool) $row->is_active,
|
||||
'disable_footer_code' => (bool) ($row->disable_footer_code ?? false),
|
||||
'created_at' => $row->created_at ?? now(),
|
||||
'updated_at' => $row->updated_at ?? $row->created_at ?? now(),
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
// created_at/updated_at sind nicht fillable und würden von updateOrCreate
|
||||
// verworfen → explizit per forceFill setzen (Muster PressReleaseImporter).
|
||||
$company->forceFill([
|
||||
'created_at' => $row->created_at ?? now(),
|
||||
'updated_at' => $row->updated_at ?? $row->created_at ?? now(),
|
||||
])->save();
|
||||
|
||||
// Pivot-Zuordnungen (member + responsible)
|
||||
$pivotPayload = [];
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@ class ContactImporter
|
|||
|
||||
DB::connection($conn)
|
||||
->table('contact')
|
||||
->when($ctx->since, fn ($query) => $query->where(function ($window) use ($ctx): void {
|
||||
$window->where('created_at', '>=', $ctx->since)
|
||||
->orWhere('updated_at', '>=', $ctx->since);
|
||||
}))
|
||||
->orderBy('id')
|
||||
->chunk(self::CHUNK_SIZE, function ($rows) use ($ctx, $result, $legacyPortal, $portal): void {
|
||||
foreach ($rows as $row) {
|
||||
|
|
@ -93,12 +97,17 @@ class ContactImporter
|
|||
'phone' => $this->cleanText($row->phone, 255),
|
||||
'fax' => $this->cleanText($row->fax, 255),
|
||||
'email' => $this->cleanText($row->email, 190),
|
||||
'created_at' => $row->created_at ?? now(),
|
||||
'updated_at' => $row->updated_at ?? $row->created_at ?? now(),
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
// created_at/updated_at sind nicht fillable und würden von updateOrCreate
|
||||
// verworfen → explizit per forceFill setzen (Muster PressReleaseImporter).
|
||||
$contact->forceFill([
|
||||
'created_at' => $row->created_at ?? now(),
|
||||
'updated_at' => $row->updated_at ?? $row->created_at ?? now(),
|
||||
])->save();
|
||||
|
||||
LegacyImportMap::query()->updateOrCreate(
|
||||
[
|
||||
'legacy_portal' => $legacyPortal,
|
||||
|
|
|
|||
|
|
@ -3,9 +3,14 @@
|
|||
namespace App\Services\Import;
|
||||
|
||||
use App\Enums\Portal;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
/**
|
||||
* Hält den Kontext für einen Import-Lauf.
|
||||
*
|
||||
* `since` schränkt den Quell-Scan auf Legacy-Zeilen ein, deren
|
||||
* created_at ODER updated_at ab dem Stichtag liegt (Delta-Läufe) —
|
||||
* Kategorien und link-associations bleiben davon unberührt.
|
||||
*/
|
||||
final class ImportContext
|
||||
{
|
||||
|
|
@ -17,6 +22,7 @@ final class ImportContext
|
|||
public readonly string $portal, // 'presseecho' | 'businessportal24' | 'all'
|
||||
public readonly bool $dryRun = false,
|
||||
public readonly bool $force = false,
|
||||
public readonly ?Carbon $since = null,
|
||||
) {
|
||||
if ($portal === 'all') {
|
||||
$this->portalEnum = null;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,10 @@ class PressReleaseImporter
|
|||
|
||||
DB::connection($conn)
|
||||
->table('press_release')
|
||||
->when($ctx->since, fn ($query) => $query->where(function ($window) use ($ctx): void {
|
||||
$window->where('created_at', '>=', $ctx->since)
|
||||
->orWhere('updated_at', '>=', $ctx->since);
|
||||
}))
|
||||
->orderBy('id')
|
||||
->chunk(self::CHUNK_SIZE, function ($rows) use ($ctx, $result, $legacyPortal, $portal, $images, $prContacts): void {
|
||||
foreach ($rows as $row) {
|
||||
|
|
|
|||
|
|
@ -92,6 +92,10 @@ class UserImporter
|
|||
'sf_guard_user_profile.tax_exempt_reason',
|
||||
'sf_guard_user_profile.disable_footer_code',
|
||||
])
|
||||
->when($ctx->since, fn ($query) => $query->where(function ($window) use ($ctx): void {
|
||||
$window->where('sf_guard_user.created_at', '>=', $ctx->since)
|
||||
->orWhere('sf_guard_user.updated_at', '>=', $ctx->since);
|
||||
}))
|
||||
->orderBy('sf_guard_user.id')
|
||||
->chunk(self::CHUNK_SIZE, function ($rows) use ($ctx, $result, $portal, $legacyPortal, $userGroups): void {
|
||||
foreach ($rows as $row) {
|
||||
|
|
@ -163,15 +167,18 @@ class UserImporter
|
|||
'last_login_ip' => $row->ip_address ?: null,
|
||||
'legacy_portal' => $legacyPortal,
|
||||
'legacy_id' => $row->legacy_id,
|
||||
'created_at' => $row->created_at ?? now(),
|
||||
'updated_at' => $row->updated_at ?? $row->created_at ?? now(),
|
||||
// Kein Passwort – User erhält Go-Live-Reset-Mail (D-09)
|
||||
]
|
||||
);
|
||||
|
||||
// is_super_admin ist nicht mass-assignable (siehe User::$fillable) –
|
||||
// im vertrauenswürdigen Import explizit per forceFill setzen.
|
||||
$user->forceFill(['is_super_admin' => (bool) $row->is_super_admin])->save();
|
||||
// is_super_admin und die Timestamps sind nicht mass-assignable und
|
||||
// würden von updateOrCreate verworfen – im vertrauenswürdigen Import
|
||||
// explizit per forceFill setzen (Muster PressReleaseImporter).
|
||||
$user->forceFill([
|
||||
'is_super_admin' => (bool) $row->is_super_admin,
|
||||
'created_at' => $row->created_at ?? now(),
|
||||
'updated_at' => $row->updated_at ?? $row->created_at ?? now(),
|
||||
])->save();
|
||||
|
||||
return $user;
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue