$item) { $currentSummaries = $item["summary"]; if ($index == 0) { foreach ($currentSummaries as $summaryItem) { $result[] = $summaryItem; } continue; } foreach ($groupInfo["summaryTypes"] as $si => $stItem) { if ($stItem == self::MIN_OP) { if ($result[$si] > $currentSummaries[$si]) { $result[$si] = $currentSummaries[$si]; } continue; } if ($stItem == self::MAX_OP) { if ($result[$si] < $currentSummaries[$si]) { $result[$si] = $currentSummaries[$si]; } continue; } $result[$si] += $currentSummaries[$si]; } } foreach ($groupInfo["summaryTypes"] as $si => $stItem) { if ($stItem == self::AVG_OP) { $result[$si] /= $itemsCount; } } $dataItem["summary"] = $result; } } private static function _GetNewDataItem($row, $groupInfo) { $dataItem = array(); $dataFieldCount = count($groupInfo["dataFieldNames"]); for ($index = 0; $index < $dataFieldCount; $index++) { $dataItem[$groupInfo["dataFieldNames"][$index]] = $row[$groupInfo["groupCount"] + $index]; } return $dataItem; } private static function _GetNewGroupItem($row, $groupInfo, $explicitKey = null) { $groupIndexOffset = $groupInfo["lastGroupExpanded"] ? 1 : 2; // Direkt row değerini al, explode kullanma $item = $explicitKey !== null ? $explicitKey : (isset($row[$groupInfo["groupIndex"]]) ? trim($row[$groupInfo["groupIndex"]]) : null); $groupItem = array(); $groupItem["key"] = ($item === "" || $item === null) ? null : $item; $groupItem["items"] = $groupInfo["groupIndex"] < $groupInfo["groupCount"] - $groupIndexOffset ? array() : ($groupInfo["lastGroupExpanded"] ? array() : NULL); if ($groupInfo["groupIndex"] == $groupInfo["groupCount"] - $groupIndexOffset) { if (isset($groupInfo["summaryTypes"])) { $summaries = array(); $endIndex = $groupInfo["groupIndex"] + count($groupInfo["summaryTypes"]) + 1; for ($index = $groupInfo["groupCount"]; $index <= $endIndex; $index++) { $summaries[] = $row[$index]; } $groupItem["summary"] = $summaries; } if (!$groupInfo["lastGroupExpanded"]) { $groupItem["count"] = $row[$groupInfo["groupIndex"] + 1]; } else { $groupItem["items"][] = self::_GetNewDataItem($row, $groupInfo); } } return $groupItem; } private static function _GroupData($row, &$resultItems, $groupInfo) { $itemsCount = count($resultItems); if (!isset($row) && !$itemsCount) { return; } $currentItem = NULL; $groupIndexOffset = $groupInfo["lastGroupExpanded"] ? 1 : 2; // Eğer bu bir tarih filtresi ise, özel yönetim yapalım $dateSequenceInfo = self::_getDateSequence($groupInfo); if ($dateSequenceInfo['isDateSequence']) { // Tarih sırası algılandı, özel tarih işleme mantığını kullan self::_processDateSequence($row, $resultItems, $groupInfo, $dateSequenceInfo); return; } // Standart (tarih olmayan) gruplamalar için normal akış $currentKey = isset($row[$groupInfo["groupIndex"]]) ? trim($row[$groupInfo["groupIndex"]]) : null; // Comma separation logic if (isset($groupInfo["processCommas"]) && $groupInfo["processCommas"] === true && $currentKey !== null && strpos($currentKey, ',') !== false) { $keys = explode(',', $currentKey); foreach ($keys as $key) { self::_processGroupDataItem($row, $resultItems, $groupInfo, trim($key)); } return; } // Standart grup işlemlerini yapan yardımcı fonksiyon self::_processGroupDataItem($row, $resultItems, $groupInfo, $currentKey); } // Standart grup işlemlerini yapan yardımcı fonksiyon private static function _processGroupDataItem($row, &$resultItems, $groupInfo, $explicitKey = null) { $currentKey = $explicitKey; if ($currentKey === "") { $currentKey = null; } $groupIndexOffset = $groupInfo["lastGroupExpanded"] ? 1 : 2; // Eğer bu key zaten varsa, ilgili item'ı kullan $keyExists = false; $currentItem = null; foreach($resultItems as $index => $item) { if(isset($item["key"]) && (trim($item["key"]) === trim($currentKey) || ($item["key"] === null && ($currentKey === null || $currentKey === "")))) { $keyExists = true; $currentItem = &$resultItems[$index]; break; } } if (!$keyExists) { $currentItem = self::_GetNewGroupItem($row, $groupInfo, $currentKey); $resultItems[] = &$currentItem; } else { // MERGE LOGIC for leaf groups if ($groupInfo["groupIndex"] == $groupInfo["groupCount"] - $groupIndexOffset) { // Update count if (isset($currentItem["count"])) { $currentItem["count"] += $row[$groupInfo["groupIndex"] + 1]; } // Update summaries if needed if (isset($currentItem["summary"]) && isset($groupInfo["summaryTypes"])) { $newSummaries = array(); $endIndex = $groupInfo["groupIndex"] + count($groupInfo["summaryTypes"]) + 1; for ($index = $groupInfo["groupCount"]; $index <= $endIndex; $index++) { $newSummaries[] = $row[$index]; } foreach ($groupInfo["summaryTypes"] as $si => $stItem) { if ($stItem == self::MIN_OP) { if ($currentItem["summary"][$si] > $newSummaries[$si]) $currentItem["summary"][$si] = $newSummaries[$si]; } else if ($stItem == self::MAX_OP) { if ($currentItem["summary"][$si] < $newSummaries[$si]) $currentItem["summary"][$si] = $newSummaries[$si]; } else if ($stItem == self::SUM_OP || $stItem == self::COUNT_OP) { $currentItem["summary"][$si] += $newSummaries[$si]; } else if ($stItem == self::AVG_OP) { $count1 = isset($currentItem["count"]) ? $currentItem["count"] : 1; $count2 = isset($row[$groupInfo["groupIndex"] + 1]) ? $row[$groupInfo["groupIndex"] + 1] : 1; if (($count1 + $count2) > 0) $currentItem["summary"][$si] = (($currentItem["summary"][$si] * $count1) + ($newSummaries[$si] * $count2)) / ($count1 + $count2); else $currentItem["summary"][$si] = ($currentItem["summary"][$si] + $newSummaries[$si]) / 2; } } } // If expanded, append items if ($groupInfo["lastGroupExpanded"]) { $currentItem["items"][] = self::_GetNewDataItem($row, $groupInfo); } } } if ($groupInfo["groupIndex"] < $groupInfo["groupCount"] - $groupIndexOffset) { $groupInfo["groupIndex"]++; self::_GroupData($row, $currentItem["items"], $groupInfo); } } // Tarih dizisini tanımla ve işle private static function _getDateSequence($groupInfo) { // Tarih sırası bilgisi $result = [ 'isDateSequence' => false, 'sequence' => [] ]; if (!isset($groupInfo["groupNames"]) || count($groupInfo["groupNames"]) < 2) { return $result; } $dateFields = []; // Tüm tarih alanlarını tespit et foreach ($groupInfo["groupNames"] as $index => $name) { if (strpos($name, 'dx_') !== 0) { continue; } $type = ''; if (strpos($name, '_year') !== false) { $type = 'year'; } else if (strpos($name, '_month') !== false) { $type = 'month'; } else if (strpos($name, '_day') !== false) { $type = 'day'; } else { continue; } $dateFields[] = [ 'index' => $index, 'type' => $type, 'name' => $name ]; } // Eğer en az 2 tarih alanı varsa, tarih sırası oluştur if (count($dateFields) >= 2) { // Yıl, ay, gün sırasına göre sırala usort($dateFields, function($a, $b) { $order = ['year' => 0, 'month' => 1, 'day' => 2]; return $order[$a['type']] - $order[$b['type']]; }); $result['isDateSequence'] = true; $result['sequence'] = $dateFields; } return $result; } // Tarih dizisini doğru bir şekilde işle private static function _processDateSequence($row, &$resultItems, $groupInfo, $dateSequenceInfo) { $groupIndexOffset = $groupInfo["lastGroupExpanded"] ? 1 : 2; $sequence = $dateSequenceInfo['sequence']; // İlk seviye için gruplama yap (genellikle yıl) $firstLevelIndex = $sequence[0]['index']; $firstLevelType = $sequence[0]['type']; $currentKey = isset($row[$firstLevelIndex]) ? trim($row[$firstLevelIndex]) : null; if ($currentKey === "") { $currentKey = null; } // İlk seviyede (yıl) item ara $yearItem = null; foreach($resultItems as &$item) { if(isset($item["key"]) && (trim($item["key"]) === trim($currentKey) || ($item["key"] === null && ($currentKey === null || $currentKey === "")))) { $yearItem = &$item; break; } } // Yıl item'ı yoksa oluştur if ($yearItem === null) { // Özel yıl item'ı oluştur $tempGroupInfo = $groupInfo; $tempGroupInfo["groupIndex"] = $firstLevelIndex; $yearItem = self::_GetNewGroupItem($row, $tempGroupInfo); $yearItem["dateLevel"] = $firstLevelType; $resultItems[] = &$yearItem; } // İkinci seviye için (genellikle ay) if (count($sequence) > 1) { $secondLevelIndex = $sequence[1]['index']; $secondLevelType = $sequence[1]['type']; $secondKey = isset($row[$secondLevelIndex]) ? trim($row[$secondLevelIndex]) : null; if ($secondKey === "") { $secondKey = null; } // İkinci seviyede (ay) item ara $monthItem = null; foreach($yearItem["items"] as &$item) { if(isset($item["key"]) && (trim($item["key"]) === trim($secondKey) || ($item["key"] === null && ($secondKey === null || $secondKey === "")))) { $monthItem = &$item; break; } } // Ay item'ı yoksa oluştur if ($monthItem === null) { // Özel ay item'ı oluştur $tempGroupInfo = $groupInfo; $tempGroupInfo["groupIndex"] = $secondLevelIndex; $monthItem = self::_GetNewGroupItem($row, $tempGroupInfo); $monthItem["dateLevel"] = $secondLevelType; $yearItem["items"][] = &$monthItem; } // Üçüncü seviye için (genellikle gün) if (count($sequence) > 2) { $thirdLevelIndex = $sequence[2]['index']; $thirdLevelType = $sequence[2]['type']; $thirdKey = isset($row[$thirdLevelIndex]) ? trim($row[$thirdLevelIndex]) : null; if ($thirdKey === "") { $thirdKey = null; } // Üçüncü seviyede (gün) item ara $dayItem = null; foreach($monthItem["items"] as &$item) { if(isset($item["key"]) && (trim($item["key"]) === trim($thirdKey) || ($item["key"] === null && ($thirdKey === null || $thirdKey === "")))) { $dayItem = &$item; break; } } // Gün item'ı yoksa oluştur if ($dayItem === null) { // Özel gün item'ı oluştur $tempGroupInfo = $groupInfo; $tempGroupInfo["groupIndex"] = $thirdLevelIndex; $dayItem = self::_GetNewGroupItem($row, $tempGroupInfo); $dayItem["dateLevel"] = $thirdLevelType; $monthItem["items"][] = &$dayItem; } // Veriler için if ($groupInfo["lastGroupExpanded"]) { $dataItem = self::_GetNewDataItem($row, $groupInfo); $dayItem["items"][] = $dataItem; } } else if ($groupInfo["lastGroupExpanded"]) { // İki seviye varsa (sadece yıl ve ay), veriyi ay seviyesinde göster $dataItem = self::_GetNewDataItem($row, $groupInfo); $monthItem["items"][] = $dataItem; } } else if ($groupInfo["lastGroupExpanded"]) { // Tek seviye varsa (sadece yıl), veriyi yıl seviyesinde göster $dataItem = self::_GetNewDataItem($row, $groupInfo); $yearItem["items"][] = $dataItem; } } public static function GetGroupedDataFromQuery($queryResult, $groupSettings) { $result = array(); $row = NULL; $groupSummaryTypes = NULL; $dataFieldNames = NULL; $startSummaryFieldIndex = NULL; $endSummaryFieldIndex = NULL; if ($groupSettings["lastGroupExpanded"]) { $queryFields = $queryResult->fetch_fields(); $dataFieldNames = array(); for ($i = $groupSettings["groupCount"]; $i < count($queryFields); $i++) { $dataFieldNames[] = $queryFields[$i]->name; } } if (isset($groupSettings["summaryTypes"])) { $groupSummaryTypes = $groupSettings["summaryTypes"]; $startSummaryFieldIndex = $groupSettings["groupCount"] - 1; $endSummaryFieldIndex = $startSummaryFieldIndex + count($groupSummaryTypes); } // Grup isimlerini al (tarih filtreleri için gerekli) $groupNames = array(); if (isset($groupSettings["groupNames"])) { $groupNames = $groupSettings["groupNames"]; } elseif ($queryResult && $queryResult->field_count > 0) { $fields = $queryResult->fetch_fields(); for ($i = 0; $i < $groupSettings["groupCount"]; $i++) { if (isset($fields[$i])) { $groupNames[] = $fields[$i]->name; } } // Sonuçlar için yeniden başa dönmek gerek $queryResult->data_seek(0); } // Tarih alanlarını sıralamak için düzenleme (yıl, ay, gün) $dateGroupIndices = self::getDateGroupIndices($groupNames); $groupInfo = array( "groupCount" => $groupSettings["groupCount"], "groupIndex" => 0, "summaryTypes" => $groupSummaryTypes, "lastGroupExpanded" => $groupSettings["lastGroupExpanded"], "dataFieldNames" => $dataFieldNames, "processCommas" => isset($groupSettings["processCommas"]) ? $groupSettings["processCommas"] : true, "groupNames" => $groupNames, "dateGroupIndices" => $dateGroupIndices ); while ($row = $queryResult->fetch_array(MYSQLI_NUM)) { if (isset($startSummaryFieldIndex)) { for ($i = $startSummaryFieldIndex; $i <= $endSummaryFieldIndex; $i++) { $row[$i] = Utils::StringToNumber($row[$i]); } } self::_GroupData($row, $result, $groupInfo); } if (!$groupSettings["lastGroupExpanded"]) { self::_GroupData($row, $result, $groupInfo); } else { if (isset($groupSettings["skip"]) && $groupSettings["skip"] >= 0 && isset($groupSettings["take"]) && $groupSettings["take"] >= 0) { $result = array_slice($result, $groupSettings["skip"], $groupSettings["take"]); } } return $result; } private static function getDateGroupIndices($groupNames) { $yearIndex = -1; $monthIndex = -1; $dayIndex = -1; foreach ($groupNames as $index => $name) { if (strpos($name, 'dx_') === 0) { if (strpos($name, '_year') !== false) { $yearIndex = $index; } else if (strpos($name, '_month') !== false) { $monthIndex = $index; } else if (strpos($name, '_day') !== false) { $dayIndex = $index; } } } return [ 'year' => $yearIndex, 'month' => $monthIndex, 'day' => $dayIndex ]; } public static function IsLastGroupExpanded($items) { $result = true; $itemsCount = count($items); if ($itemsCount > 0) { $lastItem = $items[$itemsCount - 1]; if (gettype($lastItem) === "object") { $result = isset($lastItem->isExpanded) ? $lastItem->isExpanded === true : true; } else { $result = true; } } return $result; } public static function GetFieldSetBySelectors($items) { $group = ""; $sort = ""; $select = ""; foreach ($items as $item) { $groupField = NULL; $sortField = NULL; $selectField = NULL; $desc = false; if (is_string($item) && strlen($item = trim($item))) { $selectField = $groupField = $sortField = Utils::QuoteStringValue($item); } else if (gettype($item) === "object" && isset($item->selector)) { $quoteSelector = Utils::QuoteStringValue($item->selector); $desc = isset($item->desc) ? $item->desc : false; // Tarih gruplamalarını düzenle if (isset($item->groupInterval)) { if (is_int($item->groupInterval)) { $groupField = Utils::QuoteStringValue(sprintf("%s%s_%d", self::GENERATED_FIELD_PREFIX, $item->selector, $item->groupInterval)); $selectField = sprintf("(%s - (%s %% %d)) %s %s", $quoteSelector, $quoteSelector, $item->groupInterval, self::AS_OP, $groupField); } else { // Tarih gruplamalarını düzgün şekilde yap $interval = strtolower($item->groupInterval); $groupField = Utils::QuoteStringValue(sprintf("%s%s_%s", self::GENERATED_FIELD_PREFIX, $item->selector, $interval)); if ($interval == 'year') { $selectField = sprintf("YEAR(%s) %s %s", $quoteSelector, self::AS_OP, $groupField); } else if ($interval == 'month') { $selectField = sprintf("MONTH(%s) %s %s", $quoteSelector, self::AS_OP, $groupField); } else if ($interval == 'day') { $selectField = sprintf("DAY(%s) %s %s", $quoteSelector, self::AS_OP, $groupField); } else if ($interval == 'dayofweek') { $selectField = sprintf("DAYOFWEEK(%s) - 1 %s %s", $quoteSelector, self::AS_OP, $groupField); } else { $selectField = sprintf("%s(%s) %s %s", strtoupper($interval), $quoteSelector, self::AS_OP, $groupField); } } $sortField = $groupField; } else { $selectField = $groupField = $sortField = $quoteSelector; } } if (isset($selectField)) { $select .= (strlen($select) > 0 ? ", ".$selectField : $selectField); } if (isset($groupField)) { $group .= (strlen($group) > 0 ? ", ".$groupField : $groupField); } if (isset($sortField)) { $sort .= (strlen($sort) > 0 ? ", ".$sortField : $sortField). ($desc ? " DESC" : ""); } } return array( "group" => $group, "sort" => $sort, "select" => $select ); } private static function _IsSummaryTypeValid($summaryType) { return in_array($summaryType, array(self::MIN_OP, self::MAX_OP, self::AVG_OP, self::COUNT_OP, self::SUM_OP)); } public static function GetSummaryInfo($expression, $tableName = null) { $result = array(); $fields = ""; $summaryTypes = array(); foreach ($expression as $index => $item) { if (gettype($item) === "object" && isset($item->summaryType)) { $summaryType = strtoupper(trim($item->summaryType)); if (!self::_IsSummaryTypeValid($summaryType)) { continue; } $summaryTypes[] = $summaryType; $selector = (isset($item->selector) && is_string($item->selector)) ? $item->selector : null; $quotedSelector = isset($selector) ? Utils::QuoteStringValue($selector) : "1"; if (self::shouldApplyWeldedFilter($tableName, $item, $summaryType)) { $quotedSelector = self::applyWeldedFilterExpression($quotedSelector, $summaryType); } $fields .= sprintf("%s(%s) %s %sf%d", strlen($fields) > 0 ? ", ".$summaryType : $summaryType, $quotedSelector, self::AS_OP, self::GENERATED_FIELD_PREFIX, $index); } } $result["fields"] = $fields; $result["summaryTypes"] = $summaryTypes; return $result; } private static function shouldApplyWeldedFilter($tableName, $item, $summaryType) { if ($tableName !== 'weld_logs') { return false; } $hasExplicitFlag = isset($item->weldedOnly) && $item->weldedOnly; $forceByContext = SummaryContext::shouldExcludeMechanical(); if (!$hasExplicitFlag && !$forceByContext) { return false; } return in_array($summaryType, [self::SUM_OP, self::AVG_OP]); } private static function getMechanicalTypesList() { static $cachedList = null; if ($cachedList !== null) { return $cachedList; } if (function_exists('get_mechanical_joint_types')) { $types = get_mechanical_joint_types(); } else { $types = ['BJ', 'FJ', 'TH', 'CJ']; } $escaped = array_map(function($type) { $normalized = strtoupper(trim($type)); return "'" . addslashes($normalized) . "'"; }, $types); $cachedList = implode(",", $escaped); if ($cachedList === '') { $cachedList = "''"; } return $cachedList; } private static function applyWeldedFilterExpression($quotedSelector, $summaryType) { $mechanicalList = self::getMechanicalTypesList(); $typeColumnExpr = "UPPER(TRIM(COALESCE(`type_of_welds`, '')))"; $thenValue = $summaryType === self::AVG_OP ? "NULL" : "0"; return sprintf( "CASE WHEN %s IN (%s) THEN %s ELSE %s END", $typeColumnExpr, $mechanicalList, $thenValue, $quotedSelector ); } }