true, 'resultMaster' => [], 'resultDetail' => [], 'columnsMaster' => [], 'columnsDetail' => [], 'message' => 'Cached data not found. Please click "RUN SQL" to generate report.', 'from_cache' => false ]); exit; } } // SQL sorguları için gelişmiş loglama fonksiyonu function logSqlQuery($logPrefix, $sqlCode, $logLevel = 'debug') { // Yeni satır karakterlerini boşluk ile değiştir $cleanSql = str_replace(["\r", "\n", "\t"], [" ", " ", " "], $sqlCode); // Çoklu boşlukları tek boşluğa çevir $cleanSql = preg_replace('/\s+/', ' ', $cleanSql); // Log mesajı uzunluk limiti $maxLogLength = 1000; if (strlen($cleanSql) <= $maxLogLength) { // Sorgu kısaysa tek parça olarak logla Log::$logLevel("{$logPrefix}: {$cleanSql}"); } else { // Uzun sorguları parçalara bölerek logla Log::$logLevel("{$logPrefix} (uzun sorgu - toplam uzunluk: " . strlen($cleanSql) . " karakter)"); $chunks = str_split($cleanSql, $maxLogLength); foreach ($chunks as $index => $chunk) { Log::$logLevel("{$logPrefix} [Parça " . ($index + 1) . "/" . count($chunks) . "]: {$chunk}"); } } } // Giriş parametrelerini logla Log::info("Report Builder SQL parametreleri:", [ 'document_id' => $documentId, 'sql_master_length' => strlen($sqlCodeMaster), 'sql_detail_length' => strlen($sqlCodeDetail), 'mode' => $mode ]); // Maksimum sorgu çalışma süresi (saniye) $queryTimeout = 300; // Master Query Çalıştırma if ($sqlCodeMaster && stripos(trim($sqlCodeMaster), 'SELECT') === 0) { $masterQueryStart = microtime(true); Log::info("Master sorgu başlatıldı"); logSqlQuery("Master sorgu", $sqlCodeMaster, "debug"); // Master query için de ayrı bir cache mekanizması (DB seviyesinde) kullanabiliriz // Ancak full response cache zaten en üstte var. Buradaki cache sadece live modda // tekrar eden sorguları hızlandırmak için kalabilir. $masterCacheKey = 'report_sql_master_' . md5($sqlCodeMaster); $resultMaster = Cache::get($masterCacheKey); if ($resultMaster === null) { try { $resultMaster = DB::select($sqlCodeMaster); Cache::put($masterCacheKey, $resultMaster, now()->addMinutes($cacheMinutes)); $masterQueryDuration = microtime(true) - $masterQueryStart; Log::info("Master sorgu tamamlandı", [ 'duration' => round($masterQueryDuration, 2) . " saniye", 'row_count' => count($resultMaster) ]); } catch (\Exception $queryEx) { Log::error("Master sorgu hatası: " . $queryEx->getMessage()); throw $queryEx; } } else { Log::info("Master sorgu cache'den getirildi"); } } else { $resultMaster = []; } // Detail Query Çalıştırma if ($sqlCodeDetail != "") { if (!empty($resultMaster)) { $detailQueryStart = microtime(true); // İlk sonucu al $masterData = (array)$resultMaster[0]; // Regex ile SQL'deki bind parametrelerini yakala preg_match_all('/:\w+/', $sqlCodeDetail, $matches); $params = []; // Parametreleri dolaş ve eşleştir foreach ($matches[0] as $param) { $paramName = ltrim($param, ':'); if (array_key_exists($paramName, $masterData)) { $params[$paramName] = $masterData[$paramName]; } else { throw new Exception("Master sorgusunda {$paramName} bulunamadı."); } } $detailCacheKey = 'report_sql_detail_' . md5($sqlCodeDetail . json_encode($params)); $resultDetail = Cache::get($detailCacheKey); if ($resultDetail === null) { try { $resultDetail = DB::select($sqlCodeDetail, $params); Cache::put($detailCacheKey, $resultDetail, now()->addMinutes($cacheMinutes)); } catch (\Exception $queryEx) { Log::error("Detail sorgu hatası: " . $queryEx->getMessage()); throw $queryEx; } } } else { $resultDetail = []; } } else { $resultDetail = []; } function extractFormattedColumnNames($result) { return !empty($result) ? array_map(function($column) { return '{' . $column . '}'; }, array_keys(get_object_vars($result[0]))) : []; } // Extract column names for both master and detail results $columnsMaster = extractFormattedColumnNames($resultMaster); $columnsDetail = extractFormattedColumnNames($resultDetail); $data = []; $data['success'] = true; $data['resultMaster'] = $resultMaster; try { $workPermitReplacerStart = microtime(true); $workPermitReplacer = workPermitReplacerExcel2(null, !empty($resultMaster) ? $resultMaster[0] : null, $documentInfo, ""); if ($workPermitReplacer === null) { $workPermitReplacer = []; } // Ek olarak, her satır için placeholder'ları ayrı ayrı hesaplayalım $masterRowPlaceholders = []; if (!empty($resultMaster)) { foreach ($resultMaster as $rowIndex => $rowData) { try { $rowPlaceholders = workPermitReplacerExcel2(null, $rowData, $documentInfo, ""); if ($rowPlaceholders === null) $rowPlaceholders = []; $masterRowPlaceholders[$rowIndex] = $rowPlaceholders; } catch (\Throwable $rowEx) { $masterRowPlaceholders[$rowIndex] = []; } } } $data['masterRowPlaceholders'] = $masterRowPlaceholders; } catch (\Throwable $th) { $workPermitReplacer = []; $data['message'] = $th->getMessage(); echo json_encode_tr($data); exit; } $data['resultDetail'] = $resultDetail; if (!is_array($columnsMaster)) $columnsMaster = []; if (!is_array($workPermitReplacer)) $workPermitReplacer = []; $data['columnsMaster'] = array_merge($columnsMaster, $workPermitReplacer); // Sıcaklık placeholder'larını ekle if (!empty($resultMaster) && array_key_exists('welding_date', get_object_vars($resultMaster[0])) && array_key_exists('type_of_joint', get_object_vars($resultMaster[0]))) { $customPlaceholders = []; $customPlaceholders[] = '{temp_data_ambient}'; $customPlaceholders[] = '{temp_data_material}'; if (!is_array($data['columnsMaster'])) $data['columnsMaster'] = []; $data['columnsMaster'] = array_merge($data['columnsMaster'], $customPlaceholders); } $data['columnsDetail'] = $columnsDetail; // Detail kolonları için de sıcaklık placeholder'larını ekle if (!empty($resultDetail)) { $customPlaceholders = []; $customPlaceholders[] = '{temp_data_ambient}'; $customPlaceholders[] = '{temp_data_material}'; $customPlaceholders[] = '{row_index}'; if (!is_array($data['columnsDetail'])) $data['columnsDetail'] = []; $data['columnsDetail'] = array_merge($data['columnsDetail'], $customPlaceholders); } // FULL RESPONSE CACHE KAYDETME // Tüm işlem bittikten sonra sonucu cache'e atıyoruz. Cache::put($fullCacheKey, $data, now()->addMinutes($cacheMinutes)); Log::info("Full response cache'e yazıldı: $fullCacheKey"); $endTime = microtime(true); Log::info("Report Builder SQL tamamlandı", [ 'total_duration' => round($endTime - $startTime, 2) . " saniye" ]); echo json_encode_tr($data); } catch (Exception $e) { $data = []; $data['success'] = false; $data['message'] = $e->getMessage(); Log::error("Report Builder SQL Hatası: " . $e->getMessage()); echo json_encode_tr($data); } ?>