Fix: Updating Wipe Catalog Command to force delete products instead of the soft delete
This commit is contained in:
@@ -50,7 +50,12 @@ class WipeCatalogCommand extends Command
|
|||||||
|
|
||||||
public function handle(OtpService $otp): int
|
public function handle(OtpService $otp): int
|
||||||
{
|
{
|
||||||
$productCount = Product::count();
|
// withTrashed() — a prior soft-delete-only bug in this command
|
||||||
|
// (fixed in wipe() below) could leave ghost rows a plain count()
|
||||||
|
// would never see, silently reporting "nothing to do" while they
|
||||||
|
// sit there breaking other things (e.g. the admin's own global
|
||||||
|
// search, which assumes every returned product has variants).
|
||||||
|
$productCount = Product::withTrashed()->count();
|
||||||
|
|
||||||
if ($productCount === 0) {
|
if ($productCount === 0) {
|
||||||
$this->info('No products exist — nothing to do.');
|
$this->info('No products exist — nothing to do.');
|
||||||
@@ -146,7 +151,16 @@ class WipeCatalogCommand extends Command
|
|||||||
ImportMapping::whereIn('source_type', ['product', 'variant', 'image'])->delete();
|
ImportMapping::whereIn('source_type', ['product', 'variant', 'image'])->delete();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
$products = Product::with(['variants', 'associations', 'inverseAssociations'])
|
// withTrashed(): Product/ProductVariant both use SoftDeletes
|
||||||
|
// — a plain query would stop seeing a product the moment
|
||||||
|
// forceDelete() below actually removes it, which is fine, but
|
||||||
|
// WITHOUT withTrashed() here this loop would never even
|
||||||
|
// fetch a row that a previous, buggy run of this command
|
||||||
|
// (or any other code) had already soft-deleted without
|
||||||
|
// force-deleting it. Ghost rows like that are exactly what
|
||||||
|
// this command exists to remove.
|
||||||
|
$products = Product::withTrashed()
|
||||||
|
->with(['variants' => fn ($query) => $query->withTrashed(), 'associations', 'inverseAssociations'])
|
||||||
->limit(100)
|
->limit(100)
|
||||||
->get();
|
->get();
|
||||||
|
|
||||||
@@ -161,10 +175,22 @@ class WipeCatalogCommand extends Command
|
|||||||
|
|
||||||
foreach ($product->variants as $variant) {
|
foreach ($product->variants as $variant) {
|
||||||
$variant->prices()->delete();
|
$variant->prices()->delete();
|
||||||
$variant->delete();
|
// NOT delete() — Product/ProductVariant both use
|
||||||
|
// SoftDeletes, and a plain delete() only sets
|
||||||
|
// deleted_at, leaving the row (and, for Product, its
|
||||||
|
// media) sitting in the table. This command's whole
|
||||||
|
// purpose is an irreversible wipe; a soft-deleted
|
||||||
|
// ghost row is the opposite of that. Caught in
|
||||||
|
// practice — a prior run's plain delete() left 185
|
||||||
|
// ghost Product rows with zero real variants, which
|
||||||
|
// then crashed the admin's own global search
|
||||||
|
// (Lunar\Admin\Filament\Resources\ProductResource::
|
||||||
|
// getGlobalSearchResultDetails() assumes
|
||||||
|
// $record->variants->first() is never null).
|
||||||
|
$variant->forceDelete();
|
||||||
}
|
}
|
||||||
|
|
||||||
$product->delete();
|
$product->forceDelete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user