Skip to content

Commit 6e2b9a5

Browse files
Add IndexSingleProductCommand
1 parent 17cd900 commit 6e2b9a5

File tree

1 file changed

+252
-0
lines changed

1 file changed

+252
-0
lines changed
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
<?php
2+
3+
namespace App\Console\Commands;
4+
5+
use App\Models\Product;
6+
use Illuminate\Console\Command;
7+
use Illuminate\Support\Facades\Log;
8+
9+
class IndexSingleProductCommand extends Command
10+
{
11+
/**
12+
* The name and signature of the console command.
13+
*
14+
* @var string
15+
*/
16+
protected $signature = 'scout:index-single-product {product_id?} {--all} {--force} {--published-only} {--chunk=100} {--remove-unpublished}';
17+
18+
/**
19+
* The console command description.
20+
*
21+
* @var string
22+
*/
23+
protected $description = 'Indexe un seul produit ou tous les produits dans Elasticsearch';
24+
25+
/**
26+
* Execute the console command.
27+
*
28+
* @return int
29+
*/
30+
public function handle()
31+
{
32+
$all = $this->option('all');
33+
$force = $this->option('force');
34+
$publishedOnly = $this->option('published-only');
35+
$removeUnpublished = $this->option('remove-unpublished');
36+
$chunkSize = (int) $this->option('chunk');
37+
38+
if ($all) {
39+
return $this->indexAllProducts($force, $publishedOnly, $removeUnpublished, $chunkSize);
40+
} else {
41+
$productId = $this->argument('product_id');
42+
if (!$productId) {
43+
$this->error("❌ ID du produit requis ou utilisez --all pour indexer tous les produits");
44+
return 1;
45+
}
46+
return $this->indexSingleProduct((int) $productId, $force, $removeUnpublished);
47+
}
48+
}
49+
50+
/**
51+
* Indexe un seul produit
52+
*/
53+
private function indexSingleProduct(int $productId, bool $force, bool $removeUnpublished): int
54+
{
55+
$this->info("=== Indexation du produit ID: $productId ===");
56+
57+
// 1. Trouver le produit
58+
$product = Product::with([
59+
'authors', 'productType', 'images', 'style',
60+
'materials', 'productionOrigin', 'entryMode', 'period'
61+
])->find($productId);
62+
63+
if (!$product) {
64+
$this->error("❌ Produit non trouvé avec l'ID: $productId");
65+
return 1;
66+
}
67+
68+
$this->info("✅ Produit trouvé:");
69+
$this->info(" - Inventory ID: {$product->inventory_id}");
70+
$this->info(" - Titre: {$product->title_or_designation}");
71+
$this->info(" - Publié: " . ($product->is_published ? 'Oui' : 'Non'));
72+
73+
// 2. Gérer les produits non publiés
74+
if (!$product->is_published) {
75+
76+
if ($removeUnpublished) {
77+
// Supprimer le produit de l'index Elasticsearch
78+
$this->info("🗑️ Suppression du produit non publié de l'index...");
79+
80+
try {
81+
$product->unsearchable();
82+
$this->info("✅ Produit supprimé de l'index Elasticsearch avec succès!");
83+
84+
// Log de la suppression
85+
Log::info("Produit {$product->inventory_id} (ID: $productId) supprimé de l'index Elasticsearch car non publié");
86+
87+
} catch (\Exception $e) {
88+
$this->error("❌ Erreur lors de la suppression: " . $e->getMessage());
89+
Log::error("Erreur de suppression du produit $productId", [
90+
'product_id' => $productId,
91+
'inventory_id' => $product->inventory_id,
92+
'error' => $e->getMessage(),
93+
'trace' => $e->getTraceAsString()
94+
]);
95+
return 1;
96+
}
97+
98+
$this->info("=== Suppression terminée ===");
99+
return 0;
100+
} elseif (!$force) {
101+
$this->warn("⚠️ Le produit n'est pas publié (is_published = false)");
102+
$this->warn(" Utilisez --force pour forcer l'indexation");
103+
$this->warn(" Utilisez --remove-unpublished pour supprimer de l'index");
104+
return 1;
105+
} else {
106+
$this->warn("⚠️ Indexation forcée d'un produit non publié");
107+
}
108+
}
109+
110+
// 3. Indexer le produit
111+
$this->info("🔄 Indexation en cours...");
112+
113+
try {
114+
$product->searchable();
115+
$this->info("✅ Indexation réussie!");
116+
117+
// Log du succès
118+
Log::info("Produit {$product->inventory_id} (ID: $productId) indexé avec succès dans Elasticsearch");
119+
120+
} catch (\Exception $e) {
121+
$this->error("❌ Erreur lors de l'indexation: " . $e->getMessage());
122+
Log::error("Erreur d'indexation du produit $productId", [
123+
'product_id' => $productId,
124+
'inventory_id' => $product->inventory_id,
125+
'error' => $e->getMessage(),
126+
'trace' => $e->getTraceAsString()
127+
]);
128+
return 1;
129+
}
130+
131+
$this->info("=== Indexation terminée ===");
132+
return 0;
133+
}
134+
135+
/**
136+
* Indexe tous les produits un par un
137+
*/
138+
private function indexAllProducts(bool $force, bool $publishedOnly, bool $removeUnpublished, int $chunkSize): int
139+
{
140+
$this->info("=== Indexation de tous les produits ===");
141+
$this->info("Force: " . ($force ? 'Oui' : 'Non'));
142+
$this->info("Publiés seulement: " . ($publishedOnly ? 'Oui' : 'Non'));
143+
$this->info("Supprimer non publiés: " . ($removeUnpublished ? 'Oui' : 'Non'));
144+
$this->info("Taille des lots: $chunkSize");
145+
146+
// Construire la requête
147+
$query = Product::with([
148+
'authors', 'productType', 'images', 'style',
149+
'materials', 'productionOrigin', 'entryMode', 'period'
150+
]);
151+
//$query = Product::query();
152+
153+
if ($publishedOnly && !$force) {
154+
$query->where('is_published', true);
155+
$this->info("Filtrage: produits publiés seulement");
156+
}
157+
158+
$totalProducts = $query->count();
159+
$this->info("Total des produits à traiter: $totalProducts");
160+
161+
if ($totalProducts === 0) {
162+
$this->warn("Aucun produit à indexer.");
163+
return 0;
164+
}
165+
166+
$progressBar = $this->output->createProgressBar($totalProducts);
167+
$progressBar->start();
168+
169+
$successCount = 0;
170+
$errorCount = 0;
171+
$errors = [];
172+
173+
// Traitement par lots
174+
$query->orderBy('id')->chunk($chunkSize, function ($products) use (
175+
$progressBar,
176+
$force,
177+
$removeUnpublished,
178+
&$successCount,
179+
&$errorCount,
180+
&$errors
181+
) {
182+
foreach ($products as $product) {
183+
try {
184+
// Gérer les produits non publiés
185+
if (!$product->is_published) {
186+
if ($removeUnpublished) {
187+
// Supprimer le produit de l'index
188+
$product->unsearchable();
189+
$this->line("\n🗑️ Produit {$product->inventory_id} (ID: {$product->id}) supprimé de l'index (non publié)");
190+
$successCount++;
191+
} elseif (!$force) {
192+
$this->line("\n⚠️ Produit {$product->inventory_id} (ID: {$product->id}) non publié - ignoré");
193+
} else {
194+
// Indexer le produit même s'il n'est pas publié (force)
195+
$product->searchable();
196+
$successCount++;
197+
$this->line("\n✅ Produit {$product->inventory_id} (ID: {$product->id}) indexé (forcé)");
198+
}
199+
$progressBar->advance();
200+
continue;
201+
}
202+
203+
// Indexer le produit publié
204+
$product->searchable();
205+
$successCount++;
206+
207+
$this->line("\n✅ Produit {$product->inventory_id} (ID: {$product->id}) indexé");
208+
209+
} catch (\Exception $e) {
210+
$errorCount++;
211+
$errorMessage = "Erreur lors de l'indexation du produit {$product->inventory_id} (ID: {$product->id}): " . $e->getMessage();
212+
213+
$this->error("\n" . $errorMessage);
214+
Log::error($errorMessage, [
215+
'product_id' => $product->id,
216+
'inventory_id' => $product->inventory_id,
217+
'error' => $e->getMessage()
218+
]);
219+
220+
$errors[] = [
221+
'id' => $product->id,
222+
'inventory_id' => $product->inventory_id,
223+
'error' => $e->getMessage()
224+
];
225+
}
226+
227+
$progressBar->advance();
228+
}
229+
});
230+
231+
$progressBar->finish();
232+
$this->newLine(2);
233+
234+
// Résumé
235+
$this->info("=== RÉSUMÉ DE L'INDEXATION ===");
236+
$this->info("Produits indexés avec succès: $successCount");
237+
$this->info("Produits en erreur: $errorCount");
238+
$this->info("Taux de succès: " . round(($successCount / $totalProducts) * 100, 2) . "%");
239+
240+
if (!empty($errors)) {
241+
$this->error("=== ERREURS DÉTAILLÉES ===");
242+
foreach (array_slice($errors, 0, 10) as $error) { // Limiter à 10 erreurs
243+
$this->error("ID: {$error['id']} - {$error['inventory_id']}: {$error['error']}");
244+
}
245+
if (count($errors) > 10) {
246+
$this->error("... et " . (count($errors) - 10) . " autres erreurs");
247+
}
248+
}
249+
250+
return $errorCount === 0 ? 0 : 1;
251+
}
252+
}

0 commit comments

Comments
 (0)