258 lines
10 KiB
PHP
258 lines
10 KiB
PHP
<?php
|
||
/**
|
||
* @api-readonly
|
||
* Executes report builder SQL queries
|
||
*/
|
||
try {
|
||
// İşlem başlangıç zamanını kaydet
|
||
$startTime = microtime(true);
|
||
Log::info("Report Builder SQL başlatıldı - ".date('Y-m-d H:i:s'));
|
||
|
||
$sqlCodeMaster = post("sqlCodeMaster");
|
||
$sqlCodeDetail = post("sqlCodeDetail");
|
||
$documentId = post("documentId");
|
||
$documentInfo = document_template($documentId);
|
||
$temperatures = j(setting("temperatures"));
|
||
|
||
// Mode kontrolü: 'live', 'cache_only'
|
||
$mode = post("mode");
|
||
if (!$mode) {
|
||
$mode = post("fast") == "ok" ? "cache_only" : "live"; // Geriye dönük uyumluluk
|
||
}
|
||
|
||
$cacheMinutes = 60; // Cache süresi (dakika cinsinden)
|
||
|
||
// Full Response Cache Key
|
||
// Bu key, tüm işlem sonucunu (master, detail, columns, placeholders) saklar.
|
||
$fullCacheKey = 'report_full_response_' . md5($documentId . $sqlCodeMaster . $sqlCodeDetail);
|
||
|
||
if ($mode == 'cache_only') {
|
||
Log::info("Cache Only modu aktif. Full cache kontrol ediliyor: $fullCacheKey");
|
||
$cachedResponse = Cache::get($fullCacheKey);
|
||
|
||
if ($cachedResponse !== null) {
|
||
Log::info("Full cache bulundu, direkt döndürülüyor.");
|
||
echo json_encode_tr($cachedResponse);
|
||
exit;
|
||
} else {
|
||
Log::info("Full cache bulunamadı. Boş yanıt döndürülüyor (Hesaplama yapılmayacak).");
|
||
// Cache yoksa, kullanıcıya boş ama geçerli bir yapı dönüyoruz ki hata almasın
|
||
// Kullanıcı "Run SQL" butonuna basarak veriyi oluşturabilir.
|
||
echo json_encode_tr([
|
||
'success' => 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);
|
||
}
|
||
?>
|