header('X-Token'); $orgHeader = $request->header('X-Organisation'); if (empty($tokenHeader) || empty($orgHeader)) { return response()->json([ 'success' => false, 'message' => 'X-Token and X-Organisation headers are required.' ], 401); } $user = AuthHelper::verifyAuth(); $linkedOrg = AuthHelper::getOrganisationName(); if ($linkedOrg !== $orgHeader) { return response()->json([ 'success' => false, 'message' => 'Organisation mismatch. Token does not belong to the requested organisation.' ], 403); } // 2. Validate at least one image is present if (!$request->hasFile('images')) { return response()->json([ 'success' => false, 'message' => 'No image files provided. Use images[] field.' ], 400); } $files = $request->file('images'); // Normalise to array (handles both single and multiple) if (!is_array($files)) { $files = [$files]; } // 3. Determine storage path $orgFolder = preg_replace('/_lms$/i', '', $linkedOrg); $galleryPath = 'gallery/' . $orgFolder; if (!Storage::disk('public')->exists($galleryPath)) { Storage::disk('public')->makeDirectory($galleryPath); } // 4. Connect to org DB once (outside the loop) DBConnectionHelper::connectToOrganisation($linkedOrg); $uploaded = []; $failed = []; foreach ($files as $index => $file) { // Skip invalid files instead of aborting the whole request if (!$file || !$file->isValid()) { $failed[] = [ 'index' => $index, 'message' => 'Invalid or missing file.', ]; continue; } try { // 5. Process & compress image $manager = new ImageManager(new GdDriver()); $image = $manager->read($file->getPathname()); if ($image->width() > self::MAX_DIMENSION || $image->height() > self::MAX_DIMENSION) { $image = $image->scaleDown(self::MAX_DIMENSION, self::MAX_DIMENSION); } $compressedData = $image->encode(new WebpEncoder(quality: self::COMPRESS_QUALITY)); // 6. Generate unique filename and store $fileName = time() . '_' . uniqid() . '.webp'; $storagePath = $galleryPath . '/' . $fileName; Storage::disk('public')->put($storagePath, (string) $compressedData); $url = Storage::disk('public')->url($storagePath); // 7. Insert DB record $now = now()->format('Y-m-d H:i:s'); $galleryId = DB::connection('dynamic')->table('gallery')->insertGetId([ 'organisation' => $linkedOrg, 'image_name' => $fileName, 'image_url' => $url, 'uploaded_by' => (int) $user->id, 'created_at' => $now, 'updated_at' => $now, ]); $uploaded[] = [ 'id' => $galleryId, 'image_url' => $url, 'file_name' => $fileName, ]; } catch (\Throwable $e) { $failed[] = [ 'index' => $index, 'message' => $e->getMessage(), ]; } } // 8. Return combined result $allFailed = count($uploaded) === 0; return response()->json([ 'success' => !$allFailed, 'message' => $allFailed ? 'All uploads failed.' : (count($failed) > 0 ? 'Some images uploaded successfully.' : 'All images uploaded successfully.'), 'organisation' => $linkedOrg, 'folder' => $orgFolder, 'uploaded' => $uploaded, 'failed' => $failed, 'total' => count($files), 'total_uploaded' => count($uploaded), 'total_failed' => count($failed), ], $allFailed ? 500 : 200); } catch (\Throwable $e) { return response()->json([ 'success' => false, 'message' => 'Exception: ' . $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine() ], 500); } } }