Files
2026-04-28 21:14:25 +03:00

645 lines
27 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace App\DevExtreme;
use App\DevExtreme\SummaryContext;
class AggregateHelper {
const MIN_OP = "MIN";
const MAX_OP = "MAX";
const AVG_OP = "AVG";
const COUNT_OP = "COUNT";
const SUM_OP = "SUM";
const AS_OP = "AS";
const GENERATED_FIELD_PREFIX = "dx_";
private static function _RecalculateGroupCountAndSummary(&$dataItem, $groupInfo) {
if ($groupInfo["groupIndex"] <= $groupInfo["groupCount"] - 3) {
$items = $dataItem["items"];
foreach ($items as $item) {
$grInfo = $groupInfo;
$grInfo["groupIndex"]++;
self::_RecalculateGroupCountAndSummary($item, $grInfo);
}
}
if (isset($groupInfo["summaryTypes"]) && $groupInfo["groupIndex"] < $groupInfo["groupCount"] - 2) {
$result = array();
$items = $dataItem["items"];
$itemsCount = count($items);
foreach ($items as $index => $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
);
}
}