İlk temizlik tamamlandı bir önceki projeden
This commit is contained in:
@@ -0,0 +1,644 @@
|
||||
<?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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
namespace App\DevExtreme;
|
||||
class DataSourceLoader {
|
||||
public static function Load($dbSet, $params, $module = null) {
|
||||
$result = NULL;
|
||||
if (isset($dbSet) && get_class($dbSet) == "App\DevExtreme\DbSet" && isset($params) && is_array($params)) {
|
||||
// Check if distinctColumn parameter is provided (for header filter unique values)
|
||||
// distinctColumn can come as string (from GET) or already parsed
|
||||
$distinctColumn = null;
|
||||
if (isset($params["distinctColumn"])) {
|
||||
$distinctColumn = $params["distinctColumn"];
|
||||
// If it's a JSON string, decode it
|
||||
if (is_string($distinctColumn) && (substr($distinctColumn, 0, 1) === '[' || substr($distinctColumn, 0, 1) === '{')) {
|
||||
$decoded = json_decode($distinctColumn, true);
|
||||
if ($decoded !== null) {
|
||||
$distinctColumn = $decoded;
|
||||
}
|
||||
}
|
||||
// Log for debugging
|
||||
error_log("DataSourceLoader: distinctColumn parameter received: " . var_export($distinctColumn, true) . " (type: " . gettype($distinctColumn) . ")");
|
||||
}
|
||||
|
||||
if (!empty($distinctColumn) && is_string($distinctColumn)) {
|
||||
|
||||
// Apply filters first
|
||||
$dbSet->Filter(Utils::GetItemValueOrDefault($params, "filter"));
|
||||
|
||||
if ($module === 'weldlog-employer-view' && $dbSet->getTableName() === 'weld_logs') {
|
||||
self::ApplyEmployerViewFilters($dbSet);
|
||||
}
|
||||
|
||||
// Get distinct values
|
||||
error_log("DataSourceLoader: Getting distinct values for column: " . $distinctColumn . " in table: " . $dbSet->getTableName());
|
||||
$distinctValues = $dbSet->GetDistinctValues($distinctColumn);
|
||||
if ($dbSet->GetLastError() !== NULL) {
|
||||
error_log("GetDistinctValues error: " . $dbSet->GetLastError());
|
||||
// Return error response instead of NULL
|
||||
$result = array();
|
||||
$result["data"] = array();
|
||||
$result["hasBlanks"] = false;
|
||||
$result["error"] = $dbSet->GetLastError();
|
||||
return $result;
|
||||
}
|
||||
error_log("DataSourceLoader: Found " . count($distinctValues) . " distinct values");
|
||||
|
||||
// Check for blanks
|
||||
$hasBlanks = $dbSet->HasBlanks($distinctColumn);
|
||||
if ($dbSet->GetLastError() !== NULL) {
|
||||
error_log("HasBlanks error: " . $dbSet->GetLastError());
|
||||
// Continue even if HasBlanks fails
|
||||
}
|
||||
|
||||
// Format response for header filter
|
||||
$result = array();
|
||||
$result["data"] = array_map(function($value) {
|
||||
return array("value" => $value, "text" => $value);
|
||||
}, $distinctValues);
|
||||
$result["hasBlanks"] = $hasBlanks;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Normal data loading
|
||||
$dbSet->Select(Utils::GetItemValueOrDefault($params, "select"))
|
||||
->Filter(Utils::GetItemValueOrDefault($params, "filter"));
|
||||
|
||||
if ($module === 'weldlog-employer-view' && $dbSet->getTableName() === 'weld_logs') {
|
||||
self::ApplyEmployerViewFilters($dbSet);
|
||||
}
|
||||
$totalSummary = $dbSet->GetTotalSummary(Utils::GetItemValueOrDefault($params, "totalSummary"),
|
||||
Utils::GetItemValueOrDefault($params, "filter"));
|
||||
if ($dbSet->GetLastError() !== NULL) {
|
||||
error_log("GetTotalSummary error: " . $dbSet->GetLastError());
|
||||
return $result;
|
||||
}
|
||||
$totalCount = (isset($params["requireTotalCount"]) && $params["requireTotalCount"] === true)
|
||||
? $dbSet->GetCount() : NULL;
|
||||
if ($dbSet->GetLastError() !== NULL) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$dbSet->Sort(Utils::GetItemValueOrDefault($params, "sort"));
|
||||
$groupCount = NULL;
|
||||
$skip = Utils::GetItemValueOrDefault($params, "skip");
|
||||
$take = Utils::GetItemValueOrDefault($params, "take");
|
||||
if (isset($params["group"])) {
|
||||
$groupExpression = $params["group"];
|
||||
$groupSummary = Utils::GetItemValueOrDefault($params, "groupSummary");
|
||||
$dbSet->Group($groupExpression, $groupSummary, $skip, $take);
|
||||
if (isset($params["requireGroupCount"]) && $params["requireGroupCount"] === true) {
|
||||
$groupCount = $dbSet->GetGroupCount();
|
||||
}
|
||||
}
|
||||
else {
|
||||
$dbSet->SkipTake($skip, $take);
|
||||
}
|
||||
$result = array();
|
||||
$result["data"] = $dbSet->AsArray();
|
||||
if ($dbSet->GetLastError() !== NULL) {
|
||||
return $result;
|
||||
}
|
||||
if (isset($totalCount)) {
|
||||
$result["totalCount"] = $totalCount;
|
||||
}
|
||||
if (isset($totalSummary)) {
|
||||
$result["summary"] = $totalSummary;
|
||||
}
|
||||
if (isset($groupCount)) {
|
||||
$result["groupCount"] = $groupCount;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new \Exception("Invalid params");
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply employer view specific filters to weld_logs table
|
||||
* Filters:
|
||||
* 1. Exclude records with repair_status = 'Repair' in repair_logs
|
||||
* 2. Exclude records with NDT results other than 'Accept / Годен' or empty/null
|
||||
*/
|
||||
private static function ApplyEmployerViewFilters($dbSet) {
|
||||
$weldLogsTable = $dbSet->getTableName();
|
||||
|
||||
$repairFilter = "NOT EXISTS (
|
||||
SELECT 1 FROM repair_logs
|
||||
WHERE repair_logs.iso_number = {$weldLogsTable}.iso_number
|
||||
AND repair_logs.new_joint_no = {$weldLogsTable}.no_of_the_joint_as_per_as_built_survey
|
||||
AND repair_logs.repair_status = 'Repair'
|
||||
)";
|
||||
|
||||
$ndtFields = [
|
||||
'vt_result',
|
||||
'rt_result',
|
||||
'ut_result',
|
||||
'pt_result',
|
||||
'mt_result',
|
||||
'pmi_result',
|
||||
'ferrite_result',
|
||||
'ht_result'
|
||||
];
|
||||
|
||||
$ndtFilters = [];
|
||||
foreach ($ndtFields as $field) {
|
||||
$ndtFilters[] = "({$weldLogsTable}.{$field} IN ('Accept / Годен', '') OR {$weldLogsTable}.{$field} IS NULL)";
|
||||
}
|
||||
|
||||
$ndtFilter = implode(' AND ', $ndtFilters);
|
||||
|
||||
$combinedFilter = "({$repairFilter}) AND ({$ndtFilter})";
|
||||
|
||||
$dbSet->AddCustomWhere($combinedFilter);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,624 @@
|
||||
<?php
|
||||
namespace App\DevExtreme;
|
||||
class DbSet {
|
||||
private static $SELECT_OP = "SELECT";
|
||||
private static $FROM_OP = "FROM";
|
||||
private static $WHERE_OP = "WHERE";
|
||||
private static $ORDER_OP = "ORDER BY";
|
||||
private static $GROUP_OP = "GROUP BY";
|
||||
private static $ALL_FIELDS = "*";
|
||||
private static $LIMIT_OP = "LIMIT";
|
||||
private static $INSERT_OP = "INSERT INTO";
|
||||
private static $VALUES_OP = "VALUES";
|
||||
private static $UPDATE_OP = "UPDATE";
|
||||
private static $SET_OP = "SET";
|
||||
private static $DELETE_OP = "DELETE";
|
||||
private static $MAX_ROW_INDEX = 2147483647;
|
||||
private $dbTableName;
|
||||
private $tableNameIndex = 0;
|
||||
private $lastWrappedTableName;
|
||||
private $resultQuery;
|
||||
private $mySQL;
|
||||
private $lastError;
|
||||
private $groupSettings;
|
||||
private $customWhereClause = null;
|
||||
public function __construct($mySQL, $table) {
|
||||
if (!is_a($mySQL, "\mysqli") || !isset($table)) {
|
||||
throw new \Exception("Invalid params");
|
||||
}
|
||||
$this->mySQL = $mySQL;
|
||||
$this->dbTableName = $table;
|
||||
$this->resultQuery = sprintf("%s %s %s %s",
|
||||
self::$SELECT_OP,
|
||||
self::$ALL_FIELDS,
|
||||
self::$FROM_OP,
|
||||
$this->dbTableName);
|
||||
}
|
||||
public function GetLastError() {
|
||||
return $this->lastError;
|
||||
}
|
||||
|
||||
public function getTableName() {
|
||||
return $this->dbTableName;
|
||||
}
|
||||
private function _WrapQuery() {
|
||||
$this->tableNameIndex++;
|
||||
$this->lastWrappedTableName = "{$this->dbTableName}_{$this->tableNameIndex}";
|
||||
$this->resultQuery = sprintf("%s %s %s (%s) %s %s",
|
||||
self::$SELECT_OP,
|
||||
self::$ALL_FIELDS,
|
||||
self::$FROM_OP,
|
||||
$this->resultQuery,
|
||||
AggregateHelper::AS_OP,
|
||||
$this->lastWrappedTableName);
|
||||
}
|
||||
private function _PrepareQueryForLastOperator($operator) {
|
||||
$operator = trim($operator);
|
||||
$lastOperatorPos = strrpos($this->resultQuery, " ".$operator." ");
|
||||
if ($lastOperatorPos !== false) {
|
||||
$lastBracketPos = strrpos($this->resultQuery, ")");
|
||||
if (($lastBracketPos !== false && $lastOperatorPos > $lastBracketPos) || ($lastBracketPos === false)) {
|
||||
$this->_WrapQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
public function Select($expression) {
|
||||
Utils::EscapeExpressionValues($this->mySQL, $expression);
|
||||
$this->_SelectImpl($expression);
|
||||
return $this;
|
||||
}
|
||||
private function _SelectImpl($expression, $needQuotes = true) {
|
||||
if (isset($expression)) {
|
||||
$fields = "";
|
||||
if (is_string($expression)) {
|
||||
$expression = explode(",", $expression);
|
||||
}
|
||||
if (is_array($expression)) {
|
||||
foreach ($expression as $field) {
|
||||
$fields .= (strlen($fields) ? ", " : "").($needQuotes ? Utils::QuoteStringValue(trim($field)) : trim($field));
|
||||
}
|
||||
}
|
||||
if (strlen($fields)) {
|
||||
$allFieldOperatorPos = strpos($this->resultQuery, self::$ALL_FIELDS);
|
||||
if ($allFieldOperatorPos == 7) {
|
||||
$this->resultQuery = substr_replace($this->resultQuery, $fields, 7, strlen(self::$ALL_FIELDS));
|
||||
}
|
||||
else {
|
||||
$this->_WrapQuery();
|
||||
$this->_SelectImpl($expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public function Filter($expression) {
|
||||
Utils::EscapeExpressionValues($this->mySQL, $expression);
|
||||
if (isset($expression) && is_array($expression)) {
|
||||
$result = FilterHelper::GetSqlExprByArray($expression);
|
||||
if (strlen($result)) {
|
||||
$this->_PrepareQueryForLastOperator(self::$WHERE_OP);
|
||||
$this->resultQuery .= sprintf(" %s %s",
|
||||
self::$WHERE_OP,
|
||||
$result);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom raw SQL WHERE clause
|
||||
* This is used for complex filters that cannot be expressed via FilterHelper
|
||||
* @param string $rawWhereClause Raw SQL WHERE clause (without WHERE keyword)
|
||||
* @return $this
|
||||
*/
|
||||
public function AddCustomWhere($rawWhereClause) {
|
||||
if (isset($rawWhereClause) && strlen(trim($rawWhereClause)) > 0) {
|
||||
$this->_PrepareQueryForLastOperator(self::$WHERE_OP);
|
||||
if (stripos($this->resultQuery, " " . self::$WHERE_OP . " ") !== false) {
|
||||
$this->resultQuery .= sprintf(" AND (%s)",
|
||||
trim($rawWhereClause));
|
||||
if ($this->customWhereClause === null) {
|
||||
$this->customWhereClause = trim($rawWhereClause);
|
||||
} else {
|
||||
$this->customWhereClause .= " AND (" . trim($rawWhereClause) . ")";
|
||||
}
|
||||
} else {
|
||||
$this->resultQuery .= sprintf(" %s %s",
|
||||
self::$WHERE_OP,
|
||||
trim($rawWhereClause));
|
||||
$this->customWhereClause = trim($rawWhereClause);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function Sort($expression) {
|
||||
Utils::EscapeExpressionValues($this->mySQL, $expression);
|
||||
if (isset($expression)) {
|
||||
$result = "";
|
||||
if (is_string($expression)) {
|
||||
$result = trim($expression);
|
||||
}
|
||||
if (is_array($expression)) {
|
||||
$fieldSet = AggregateHelper::GetFieldSetBySelectors($expression);
|
||||
$result = $fieldSet["sort"];
|
||||
}
|
||||
if (strlen($result)) {
|
||||
$this->_PrepareQueryForLastOperator(self::$ORDER_OP);
|
||||
$this->resultQuery .= sprintf(" %s %s",
|
||||
self::$ORDER_OP,
|
||||
$result);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function SkipTake($skip, $take) {
|
||||
$skip = (!isset($skip) || !is_int($skip) ? 0 : $skip);
|
||||
$take = (!isset($take) || !is_int($take) ? self::$MAX_ROW_INDEX : $take);
|
||||
if ($skip != 0 || $take != 0) {
|
||||
$this->_PrepareQueryForLastOperator(self::$LIMIT_OP);
|
||||
$this->resultQuery .= sprintf(" %s %0.0f, %0.0f",
|
||||
self::$LIMIT_OP,
|
||||
$skip,
|
||||
$take);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract WHERE clause from resultQuery
|
||||
* @return string WHERE clause without WHERE keyword, or empty string
|
||||
*/
|
||||
private function _ExtractWhereClause() {
|
||||
$whereClause = "";
|
||||
$wherePos = stripos($this->resultQuery, " " . self::$WHERE_OP . " ");
|
||||
if ($wherePos !== false) {
|
||||
$afterWhere = substr($this->resultQuery, $wherePos + strlen(" " . self::$WHERE_OP . " "));
|
||||
// Find the end of WHERE clause by looking for ORDER BY, GROUP BY, or LIMIT
|
||||
// Use regex to find the first occurrence of these keywords
|
||||
$endPattern = '/\s+(ORDER\s+BY|GROUP\s+BY|LIMIT)\s+/i';
|
||||
if (preg_match($endPattern, $afterWhere, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
$whereClause = trim(substr($afterWhere, 0, $matches[0][1]));
|
||||
} else {
|
||||
$whereClause = trim($afterWhere);
|
||||
}
|
||||
}
|
||||
return $whereClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get distinct values for a specific column
|
||||
* @param string $columnName Column name to get distinct values from
|
||||
* @return array Array of distinct values
|
||||
*/
|
||||
public function GetDistinctValues($columnName) {
|
||||
$result = array();
|
||||
if ($this->mySQL && isset($columnName) && strlen($columnName) > 0) {
|
||||
Utils::EscapeExpressionValues($this->mySQL, $columnName);
|
||||
$quotedColumn = Utils::QuoteStringValue($columnName);
|
||||
|
||||
// Build the distinct query - use WHERE clause from resultQuery if exists
|
||||
$distinctQuery = sprintf("%s DISTINCT %s %s %s",
|
||||
self::$SELECT_OP,
|
||||
$quotedColumn,
|
||||
self::$FROM_OP,
|
||||
$this->dbTableName);
|
||||
|
||||
// Extract WHERE clause from resultQuery (after WHERE keyword)
|
||||
$whereClause = "";
|
||||
$wherePos = stripos($this->resultQuery, " " . self::$WHERE_OP . " ");
|
||||
if ($wherePos !== false) {
|
||||
// Get everything after WHERE
|
||||
$afterWhere = substr($this->resultQuery, $wherePos + strlen(" " . self::$WHERE_OP . " "));
|
||||
|
||||
// Remove ORDER BY, GROUP BY, LIMIT if they exist (find first occurrence)
|
||||
$endPattern = '/\s+(ORDER\s+BY|GROUP\s+BY|LIMIT)\s+/i';
|
||||
if (preg_match($endPattern, $afterWhere, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
$whereClause = trim(substr($afterWhere, 0, $matches[0][1]));
|
||||
} else {
|
||||
$whereClause = trim($afterWhere);
|
||||
}
|
||||
|
||||
if (strlen($whereClause) > 0) {
|
||||
$distinctQuery .= " " . self::$WHERE_OP . " " . $whereClause;
|
||||
}
|
||||
}
|
||||
|
||||
// Also add customWhereClause if exists (from AddCustomWhere)
|
||||
if ($this->customWhereClause !== null) {
|
||||
if (strlen($whereClause) > 0) {
|
||||
$distinctQuery .= " AND (" . $this->customWhereClause . ")";
|
||||
} else {
|
||||
$distinctQuery .= " " . self::$WHERE_OP . " " . $this->customWhereClause;
|
||||
}
|
||||
}
|
||||
|
||||
// Add ORDER BY for sorted results
|
||||
$distinctQuery .= sprintf(" %s %s",
|
||||
self::$ORDER_OP,
|
||||
$quotedColumn);
|
||||
|
||||
// Limit results to prevent memory issues with very large distinct value sets
|
||||
// If there's a WHERE clause (filtered), we can return more results
|
||||
// If no filter, limit to first 1000 to prevent UI freezing
|
||||
$hasFilter = ($wherePos !== false && strlen($whereClause) > 0) || ($this->customWhereClause !== null);
|
||||
if (!$hasFilter) {
|
||||
$distinctQuery .= sprintf(" %s 1000",
|
||||
self::$LIMIT_OP);
|
||||
}
|
||||
|
||||
$this->lastError = NULL;
|
||||
$sanitizedQuery = $this->_sanitizeDateValues($distinctQuery);
|
||||
|
||||
// Debug: Log the query for troubleshooting
|
||||
error_log("GetDistinctValues SQL: " . $sanitizedQuery);
|
||||
error_log("GetDistinctValues resultQuery: " . $this->resultQuery);
|
||||
|
||||
$queryResult = $this->mySQL->query($sanitizedQuery);
|
||||
if (!$queryResult) {
|
||||
$this->lastError = $this->mySQL->error;
|
||||
error_log("GetDistinctValues query error: " . $this->lastError);
|
||||
}
|
||||
else {
|
||||
while ($row = $queryResult->fetch_array(MYSQLI_NUM)) {
|
||||
$value = $row[0];
|
||||
if ($value !== null && $value !== '') {
|
||||
$result[] = $value;
|
||||
}
|
||||
}
|
||||
$queryResult->close();
|
||||
error_log("GetDistinctValues found " . count($result) . " distinct values");
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there are blank (NULL or empty) values for a specific column
|
||||
* @param string $columnName Column name to check
|
||||
* @return bool True if blanks exist, false otherwise
|
||||
*/
|
||||
public function HasBlanks($columnName) {
|
||||
$result = false;
|
||||
if ($this->mySQL && isset($columnName) && strlen($columnName) > 0) {
|
||||
Utils::EscapeExpressionValues($this->mySQL, $columnName);
|
||||
$quotedColumn = Utils::QuoteStringValue($columnName);
|
||||
|
||||
// Build the blank check query
|
||||
$blankQuery = sprintf("%s COUNT(1) %s %s",
|
||||
self::$SELECT_OP,
|
||||
self::$FROM_OP,
|
||||
$this->dbTableName);
|
||||
|
||||
// Extract WHERE clause from resultQuery
|
||||
$wherePos = stripos($this->resultQuery, " " . self::$WHERE_OP . " ");
|
||||
$blankCondition = sprintf("(%s IS NULL OR %s = '')",
|
||||
$quotedColumn,
|
||||
$quotedColumn);
|
||||
|
||||
if ($wherePos !== false) {
|
||||
// Get everything after WHERE
|
||||
$afterWhere = substr($this->resultQuery, $wherePos + strlen(" " . self::$WHERE_OP . " "));
|
||||
|
||||
// Remove ORDER BY, GROUP BY, LIMIT if they exist
|
||||
$endPattern = '/\s+(ORDER\s+BY|GROUP\s+BY|LIMIT)\s+/i';
|
||||
if (preg_match($endPattern, $afterWhere, $matches, PREG_OFFSET_CAPTURE)) {
|
||||
$whereClause = trim(substr($afterWhere, 0, $matches[0][1]));
|
||||
} else {
|
||||
$whereClause = trim($afterWhere);
|
||||
}
|
||||
|
||||
if (strlen($whereClause) > 0) {
|
||||
$blankQuery .= " " . self::$WHERE_OP . " " . $whereClause . " AND " . $blankCondition;
|
||||
} else {
|
||||
$blankQuery .= " " . self::$WHERE_OP . " " . $blankCondition;
|
||||
}
|
||||
} else {
|
||||
// No WHERE clause, add blank condition
|
||||
$blankQuery .= " " . self::$WHERE_OP . " " . $blankCondition;
|
||||
}
|
||||
|
||||
$this->lastError = NULL;
|
||||
$sanitizedQuery = $this->_sanitizeDateValues($blankQuery);
|
||||
$queryResult = $this->mySQL->query($sanitizedQuery);
|
||||
if (!$queryResult) {
|
||||
$this->lastError = $this->mySQL->error;
|
||||
}
|
||||
else if ($queryResult->num_rows > 0) {
|
||||
$row = $queryResult->fetch_array(MYSQLI_NUM);
|
||||
$result = Utils::StringToNumber($row[0]) > 0;
|
||||
$queryResult->close();
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
private function _CreateGroupCountQuery($firstGroupField, $skip = NULL, $take = NULL) {
|
||||
$groupCount = $this->groupSettings["groupCount"];
|
||||
$lastGroupExpanded = $this->groupSettings["lastGroupExpanded"];
|
||||
if (!$lastGroupExpanded) {
|
||||
if ($groupCount === 2) {
|
||||
$this->groupSettings["groupItemCountQuery"] = sprintf("%s COUNT(1) %s (%s) AS %s_%d",
|
||||
self::$SELECT_OP,
|
||||
self::$FROM_OP,
|
||||
$this->resultQuery,
|
||||
$this->dbTableName,
|
||||
$this->tableNameIndex + 1);
|
||||
if (isset($skip) || isset($take)) {
|
||||
$this->SkipTake($skip, $take);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
$groupQuery = sprintf("%s COUNT(1) %s %s %s %s",
|
||||
self::$SELECT_OP,
|
||||
self::$FROM_OP,
|
||||
$this->dbTableName,
|
||||
self::$GROUP_OP,
|
||||
$firstGroupField);
|
||||
$this->groupSettings["groupItemCountQuery"] = sprintf("%s COUNT(1) %s (%s) AS %s_%d",
|
||||
self::$SELECT_OP,
|
||||
self::$FROM_OP,
|
||||
$groupQuery,
|
||||
$this->dbTableName,
|
||||
$this->tableNameIndex + 1);
|
||||
if (isset($skip) || isset($take)) {
|
||||
$this->groupSettings["skip"] = isset($skip) ? Utils::StringToNumber($skip) : 0;
|
||||
$this->groupSettings["take"] = isset($take) ? Utils::StringToNumber($take) : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
public function Group($expression, $groupSummary = NULL, $skip = NULL, $take = NULL) {
|
||||
Utils::EscapeExpressionValues($this->mySQL, $expression);
|
||||
Utils::EscapeExpressionValues($this->mySQL, $groupSummary);
|
||||
$this->groupSettings = NULL;
|
||||
if (isset($expression)) {
|
||||
$groupFields = "";
|
||||
$sortFields = "";
|
||||
$selectFields = "";
|
||||
$lastGroupExpanded = true;
|
||||
$groupCount = 0;
|
||||
if (is_string($expression)) {
|
||||
$selectFields = $sortFields = $groupFields = trim($expression);
|
||||
$groupCount = count(explode(",", $expression));
|
||||
}
|
||||
if (is_array($expression)) {
|
||||
$groupCount = count($expression);
|
||||
$fieldSet = AggregateHelper::GetFieldSetBySelectors($expression);
|
||||
$groupFields = $fieldSet["group"];
|
||||
$selectFields = $fieldSet["select"];
|
||||
$sortFields = $fieldSet["sort"];
|
||||
$lastGroupExpanded = AggregateHelper::IsLastGroupExpanded($expression);
|
||||
}
|
||||
if ($groupCount > 0) {
|
||||
if (!$lastGroupExpanded) {
|
||||
$groupSummaryData = isset($groupSummary) && is_array($groupSummary) ? AggregateHelper::GetSummaryInfo($groupSummary, $this->dbTableName) : NULL;
|
||||
$selectExpression = sprintf("%s, %s(1)%s",
|
||||
strlen($selectFields) ? $selectFields : $groupFields,
|
||||
AggregateHelper::COUNT_OP,
|
||||
(isset($groupSummaryData) && isset($groupSummaryData["fields"]) && strlen($groupSummaryData["fields"]) ?
|
||||
", ".$groupSummaryData["fields"] : ""));
|
||||
$groupCount++;
|
||||
$this->_WrapQuery();
|
||||
$this->_SelectImpl($selectExpression, false);
|
||||
$this->resultQuery .= sprintf(" %s %s",
|
||||
self::$GROUP_OP,
|
||||
$groupFields);
|
||||
$this->Sort($sortFields);
|
||||
}
|
||||
else {
|
||||
$this->_WrapQuery();
|
||||
$selectExpression = "{$selectFields}, {$this->lastWrappedTableName}.*";
|
||||
$this->_SelectImpl($selectExpression, false);
|
||||
$this->resultQuery .= sprintf(" %s %s",
|
||||
self::$ORDER_OP,
|
||||
$sortFields);
|
||||
}
|
||||
$lastGroupExpanded = true;
|
||||
$this->groupSettings = array();
|
||||
$this->groupSettings["groupCount"] = $groupCount;
|
||||
$this->groupSettings["lastGroupExpanded"] = $lastGroupExpanded;
|
||||
$this->groupSettings["summaryTypes"] = !$lastGroupExpanded ? $groupSummaryData["summaryTypes"] : NULL;
|
||||
$firstGroupField = explode(",", $groupFields)[0];
|
||||
$this->_CreateGroupCountQuery($firstGroupField, $skip, $take);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
public function GetTotalSummary($expression, $filterExpression = NULL) {
|
||||
Utils::EscapeExpressionValues($this->mySQL, $expression);
|
||||
Utils::EscapeExpressionValues($this->mySQL, $filterExpression);
|
||||
$result = NULL;
|
||||
if (isset($expression) && is_array($expression)) {
|
||||
$summaryInfo = AggregateHelper::GetSummaryInfo($expression, $this->dbTableName);
|
||||
$fields = $summaryInfo["fields"];
|
||||
if (strlen($fields) > 0) {
|
||||
$filter = "";
|
||||
if (isset($filterExpression)) {
|
||||
if (is_string($filterExpression)) {
|
||||
$filter = trim($filterExpression);
|
||||
}
|
||||
if (is_array($filterExpression)) {
|
||||
$filter = FilterHelper::GetSqlExprByArray($filterExpression);
|
||||
}
|
||||
}
|
||||
|
||||
$combinedFilter = "";
|
||||
if (strlen($filter) > 0 && $this->customWhereClause !== null) {
|
||||
$combinedFilter = "(" . $filter . ") AND (" . $this->customWhereClause . ")";
|
||||
} else if (strlen($filter) > 0) {
|
||||
$combinedFilter = $filter;
|
||||
} else if ($this->customWhereClause !== null) {
|
||||
$combinedFilter = $this->customWhereClause;
|
||||
}
|
||||
|
||||
$totalSummaryQuery = sprintf("%s %s %s %s %s",
|
||||
self::$SELECT_OP,
|
||||
$fields,
|
||||
self::$FROM_OP,
|
||||
$this->dbTableName,
|
||||
strlen($combinedFilter) > 0 ? self::$WHERE_OP." ".$combinedFilter : "");
|
||||
$this->lastError = NULL;
|
||||
$queryResult = $this->mySQL->query($totalSummaryQuery);
|
||||
if (!$queryResult) {
|
||||
$this->lastError = $this->mySQL->error;
|
||||
}
|
||||
else if ($queryResult->num_rows > 0) {
|
||||
$result = $queryResult->fetch_array(MYSQLI_NUM);
|
||||
foreach ($result as $i => $item) {
|
||||
$result[$i] = Utils::StringToNumber($item);
|
||||
}
|
||||
}
|
||||
if ($queryResult !== false) {
|
||||
$queryResult->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
public function GetGroupCount() {
|
||||
$result = 0;
|
||||
if ($this->mySQL && isset($this->groupSettings) && isset($this->groupSettings["groupItemCountQuery"])) {
|
||||
$this->lastError = NULL;
|
||||
$queryResult = $this->mySQL->query($this->groupSettings["groupItemCountQuery"]);
|
||||
if (!$queryResult) {
|
||||
$this->lastError = $this->mySQL->error;
|
||||
}
|
||||
else if ($queryResult->num_rows > 0) {
|
||||
$row = $queryResult->fetch_array(MYSQLI_NUM);
|
||||
$result = Utils::StringToNumber($row[0]);
|
||||
}
|
||||
if ($queryResult !== false) {
|
||||
$queryResult->close();
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
public function GetCount() {
|
||||
$result = 0;
|
||||
if ($this->mySQL) {
|
||||
$countQuery = sprintf("%s %s(1) %s (%s) %s %s_%d",
|
||||
self::$SELECT_OP,
|
||||
AggregateHelper::COUNT_OP,
|
||||
self::$FROM_OP,
|
||||
$this->resultQuery,
|
||||
AggregateHelper::AS_OP,
|
||||
$this->dbTableName,
|
||||
$this->tableNameIndex + 1);
|
||||
$this->lastError = NULL;
|
||||
$countQuery = $this->_sanitizeDateValues($countQuery);
|
||||
$queryResult = $this->mySQL->query($countQuery);
|
||||
if (!$queryResult) {
|
||||
$this->lastError = $this->mySQL->error;
|
||||
}
|
||||
else if ($queryResult->num_rows > 0) {
|
||||
$row = $queryResult->fetch_array(MYSQLI_NUM);
|
||||
$result = Utils::StringToNumber($row[0]);
|
||||
}
|
||||
if ($queryResult !== false) {
|
||||
$queryResult->close();
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
private function _sanitizeDateValues($query) {
|
||||
return preg_replace("/'0NaN-NaN-NaN'|'\d*NaN-NaN-NaN'/", "NULL", $query);
|
||||
}
|
||||
public function AsArray() {
|
||||
$result = NULL;
|
||||
if ($this->mySQL) {
|
||||
$this->lastError = NULL;
|
||||
$sanitizedQuery = $this->_sanitizeDateValues($this->resultQuery);
|
||||
$queryResult = $this->mySQL->query($sanitizedQuery);
|
||||
if (!$queryResult) {
|
||||
$this->lastError = $this->mySQL->error;
|
||||
}
|
||||
else {
|
||||
if (isset($this->groupSettings)) {
|
||||
$result = AggregateHelper::GetGroupedDataFromQuery($queryResult, $this->groupSettings);
|
||||
}
|
||||
else {
|
||||
$result = $queryResult->fetch_all(MYSQLI_ASSOC);
|
||||
}
|
||||
$queryResult->close();
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
public function Insert($values) {
|
||||
Utils::EscapeExpressionValues($this->mySQL, $values);
|
||||
$result = NULL;
|
||||
if (isset($values) && is_array($values)) {
|
||||
$fields = "";
|
||||
$fieldValues = "";
|
||||
foreach ($values as $prop => $value) {
|
||||
$fields .= (strlen($fields) ? ", " : "").Utils::QuoteStringValue($prop);
|
||||
$fieldValues .= (strlen($fieldValues) ? ", " : "").Utils::QuoteStringValue($value, false);
|
||||
}
|
||||
if (strlen($fields) > 0) {
|
||||
$queryString = sprintf("%s %s (%s) %s(%s)",
|
||||
self::$INSERT_OP,
|
||||
$this->dbTableName,
|
||||
$fields,
|
||||
self::$VALUES_OP,
|
||||
$fieldValues);
|
||||
$this->lastError = NULL;
|
||||
if ($this->mySQL->query($queryString) == true) {
|
||||
$result = $this->mySQL->affected_rows;
|
||||
}
|
||||
else {
|
||||
$this->lastError = $this->mySQL->error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
public function Update($key, $values) {
|
||||
Utils::EscapeExpressionValues($this->mySQL, $key);
|
||||
Utils::EscapeExpressionValues($this->mySQL, $values);
|
||||
$result = NULL;
|
||||
if (isset($key) && is_array($key) && isset($values) && is_array($values)) {
|
||||
$fields = "";
|
||||
foreach ($values as $prop => $value) {
|
||||
$templ = strlen($fields) == 0 ? "%s = %s" : ", %s = %s";
|
||||
$fields .= sprintf($templ,
|
||||
Utils::QuoteStringValue($prop),
|
||||
Utils::QuoteStringValue($value, false));
|
||||
}
|
||||
if (strlen($fields) > 0) {
|
||||
$queryString = sprintf("%s %s %s %s %s %s",
|
||||
self::$UPDATE_OP,
|
||||
$this->dbTableName,
|
||||
self::$SET_OP,
|
||||
$fields,
|
||||
self::$WHERE_OP,
|
||||
FilterHelper::GetSqlExprByKey($key));
|
||||
$this->lastError = NULL;
|
||||
if ($this->mySQL->query($queryString) == true) {
|
||||
$result = $this->mySQL->affected_rows;
|
||||
}
|
||||
else {
|
||||
$this->lastError = $this->mySQL->error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
public function Delete($key) {
|
||||
Utils::EscapeExpressionValues($this->mySQL, $key);
|
||||
$result = NULL;
|
||||
if (isset($key) && is_array($key)) {
|
||||
$queryString = sprintf("%s %s %s %s %s",
|
||||
self::$DELETE_OP,
|
||||
self::$FROM_OP,
|
||||
$this->dbTableName,
|
||||
self::$WHERE_OP,
|
||||
FilterHelper::GetSqlExprByKey($key));
|
||||
$this->lastError = NULL;
|
||||
if ($this->mySQL->query($queryString) == true) {
|
||||
$result = $this->mySQL->affected_rows;
|
||||
}
|
||||
else {
|
||||
$this->lastError = $this->mySQL->error;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
<?php
|
||||
namespace App\DevExtreme;
|
||||
class FilterHelper {
|
||||
private static $AND_OP = "AND";
|
||||
private static $OR_OP = "OR";
|
||||
private static $LIKE_OP = "LIKE";
|
||||
private static $NOT_OP = "NOT";
|
||||
private static $IS_OP = "IS";
|
||||
private static function _GetSqlFieldName($field) {
|
||||
$fieldParts = explode(".", $field);
|
||||
$result = "";
|
||||
$fieldName = Utils::QuoteStringValue(trim($fieldParts[0]));
|
||||
if (count($fieldParts) == 2) {
|
||||
$dateProperty = trim($fieldParts[1]);
|
||||
$sqlDateFunction = "";
|
||||
$fieldPattern = "";
|
||||
switch ($dateProperty) {
|
||||
case "year":
|
||||
case "month":
|
||||
case "day": {
|
||||
$sqlDateFunction = strtoupper($dateProperty);
|
||||
$fieldPattern = "%s(%s)";
|
||||
break;
|
||||
}
|
||||
case "dayOfWeek": {
|
||||
$sqlDateFunction = strtoupper($dateProperty);
|
||||
$fieldPattern = "%s(%s) - 1";
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new \Exception("The \"".$dateProperty."\" command is not supported");
|
||||
}
|
||||
}
|
||||
$result = sprintf($fieldPattern, $sqlDateFunction, $fieldName);
|
||||
}
|
||||
else {
|
||||
$result = $fieldName;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
private static function _GetSimpleSqlExpr($expression) {
|
||||
$result = "";
|
||||
$itemsCount = count($expression);
|
||||
$fieldName = self::_GetSqlFieldName(trim($expression[0]));
|
||||
|
||||
// Known operators list
|
||||
$knownOperators = ['=', '<>', '>', '>=', '<', '<=', 'startswith', 'endswith', 'contains', 'notcontains', 'in', '==='];
|
||||
|
||||
if ($itemsCount == 2) {
|
||||
$val = $expression[1];
|
||||
$valLower = is_string($val) ? strtolower(trim($val)) : '';
|
||||
|
||||
// Check if second element is an operator (means searching for empty values)
|
||||
if (in_array($valLower, $knownOperators)) {
|
||||
// This is an operator without value - treat as empty value search
|
||||
switch ($valLower) {
|
||||
case 'contains':
|
||||
case 'startswith':
|
||||
case 'endswith':
|
||||
case '=':
|
||||
// Search for NULL or empty string
|
||||
$result = sprintf("(%s IS NULL OR %s = '')", $fieldName, $fieldName);
|
||||
break;
|
||||
case '<>':
|
||||
case 'notcontains':
|
||||
// Search for NOT NULL and NOT empty
|
||||
$result = sprintf("(%s IS NOT NULL AND %s != '')", $fieldName, $fieldName);
|
||||
break;
|
||||
default:
|
||||
// For other operators, just check IS NULL
|
||||
$result = sprintf("%s IS NULL", $fieldName);
|
||||
break;
|
||||
}
|
||||
} elseif ($val === "(Empty)" || $val === "(Boş)" || $val === "") {
|
||||
$result = sprintf("%s IS NULL", $fieldName);
|
||||
} else {
|
||||
$result = sprintf("%s = %s", $fieldName, Utils::QuoteStringValue($val, false));
|
||||
}
|
||||
}
|
||||
else if ($itemsCount == 3) {
|
||||
$clause = strtolower(trim($expression[1]));
|
||||
$val = $expression[2];
|
||||
|
||||
if ($val === "(Empty)" || $val === "(Boş)" || $val === "" || is_null($val)) {
|
||||
switch ($clause) {
|
||||
case "=":
|
||||
case "contains":
|
||||
case "startswith":
|
||||
case "endswith": {
|
||||
// Hem NULL hem empty string için kontrol
|
||||
if(strpos($fieldName, 'date') !== false) {
|
||||
$result = sprintf("(%s IS NULL)", $fieldName);
|
||||
} else {
|
||||
$result = sprintf("(%s IS NULL OR %s = '')", $fieldName, $fieldName);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
case "<>":
|
||||
case "notcontains": {
|
||||
// Ne NULL ne de empty string
|
||||
$result = sprintf("(%s IS NOT NULL AND %s != '')", $fieldName, $fieldName);
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch ($clause) {
|
||||
case "===": {
|
||||
// Exact match - DO NOT split comma-separated values
|
||||
$result = sprintf("%s = %s", $fieldName, Utils::QuoteStringValue($val, false));
|
||||
return $result;
|
||||
}
|
||||
case "=": {
|
||||
// Exact match - treat comma-separated values as single entity
|
||||
$pattern = "%s %s %s";
|
||||
$val = Utils::QuoteStringValue($val, false);
|
||||
break;
|
||||
}
|
||||
case "<>": {
|
||||
$pattern = "%s %s %s";
|
||||
$val = Utils::QuoteStringValue($val, false);
|
||||
break;
|
||||
}
|
||||
case ">":
|
||||
case ">=":
|
||||
case "<":
|
||||
case "<=": {
|
||||
$pattern = "%s %s %s";
|
||||
$val = Utils::QuoteStringValue($val, false);
|
||||
break;
|
||||
}
|
||||
case "startswith": {
|
||||
$pattern = "%s %s '%s%%'";
|
||||
$clause = self::$LIKE_OP;
|
||||
$val = addcslashes($val, "%_");
|
||||
break;
|
||||
}
|
||||
case "endswith": {
|
||||
$pattern = "%s %s '%%%s'";
|
||||
$val = addcslashes($val, "%_");
|
||||
$clause = self::$LIKE_OP;
|
||||
break;
|
||||
}
|
||||
case "contains": {
|
||||
$pattern = "%s %s '%%%s%%'";
|
||||
$val = addcslashes($val, "%_");
|
||||
$clause = self::$LIKE_OP;
|
||||
break;
|
||||
}
|
||||
case "notcontains": {
|
||||
$pattern = "%s %s '%%%s%%'";
|
||||
$val = addcslashes($val, "%_");
|
||||
$clause = sprintf("%s %s", self::$NOT_OP, self::$LIKE_OP);
|
||||
break;
|
||||
}
|
||||
case "noneof": {
|
||||
if (is_array($val) && count($val) > 0) {
|
||||
$quotedValues = array_map(function($v) {
|
||||
return Utils::QuoteStringValue($v, false);
|
||||
}, $val);
|
||||
$result = sprintf("%s NOT IN (%s)", $fieldName, implode(", ", $quotedValues));
|
||||
return $result;
|
||||
}
|
||||
$pattern = "%s <> %s";
|
||||
$val = Utils::QuoteStringValue($val, false);
|
||||
break;
|
||||
}
|
||||
case "anyof":
|
||||
case "in": {
|
||||
if (is_array($val) && count($val) > 0) {
|
||||
$quotedValues = array_map(function($v) {
|
||||
return Utils::QuoteStringValue($v, false);
|
||||
}, $val);
|
||||
$result = sprintf("%s IN (%s)", $fieldName, implode(", ", $quotedValues));
|
||||
return $result;
|
||||
}
|
||||
// Fall through to default if not array
|
||||
}
|
||||
default: {
|
||||
$clause = $clause ?: "=";
|
||||
$pattern = "%s %s %s";
|
||||
if(!is_array($val)) {
|
||||
$val = Utils::QuoteStringValue($val, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($pattern)) {
|
||||
$result = sprintf($pattern, $fieldName, $clause, $val);
|
||||
$result = str_replace(" = ''", " is null", $result);
|
||||
} else {
|
||||
$result = ""; // Should not happen with new default logic but safe fallback
|
||||
}
|
||||
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
public static function GetSqlExprByArray($expression) {
|
||||
$result = "(";
|
||||
$prevItemWasArray = false;
|
||||
foreach ($expression as $index => $item) {
|
||||
if (is_string($item)) {
|
||||
$prevItemWasArray = false;
|
||||
if ($index == 0) {
|
||||
if ($item == "!") {
|
||||
$result .= sprintf("%s ", self::$NOT_OP);
|
||||
continue;
|
||||
}
|
||||
$result .= (isset($expression) && is_array($expression)) ? self::_GetSimpleSqlExpr($expression) : "";
|
||||
break;
|
||||
}
|
||||
$strItem = strtoupper(trim($item));
|
||||
if ($strItem == self::$AND_OP || $strItem == self::$OR_OP) {
|
||||
$result .= sprintf(" %s ", $strItem);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (is_array($item)) {
|
||||
if ($prevItemWasArray) {
|
||||
$result .= sprintf(" %s ", self::$AND_OP);
|
||||
}
|
||||
$result .= self::GetSqlExprByArray($item);
|
||||
$prevItemWasArray = true;
|
||||
}
|
||||
}
|
||||
$result .= ")";
|
||||
return $result;
|
||||
}
|
||||
public static function GetSqlExprByKey($key) {
|
||||
$result = "";
|
||||
foreach ($key as $prop => $value) {
|
||||
$templ = strlen($result) == 0 ?
|
||||
"%s = %s" :
|
||||
" ".self::$AND_OP." %s = %s";
|
||||
$result .= sprintf($templ,
|
||||
Utils::QuoteStringValue($prop),
|
||||
Utils::QuoteStringValue($value, false));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace App\DevExtreme;
|
||||
class LoadHelper {
|
||||
public static function LoadModule($className) {
|
||||
$namespaceNamePos = strpos($className, __NAMESPACE__);
|
||||
if ($namespaceNamePos === 0) {
|
||||
$subFolderPath = substr($className, $namespaceNamePos + strlen(__NAMESPACE__));
|
||||
$filePath = __DIR__.str_replace("\\", DIRECTORY_SEPARATOR, $subFolderPath).".php";
|
||||
require_once($filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\DevExtreme;
|
||||
|
||||
class SummaryContext
|
||||
{
|
||||
protected static bool $excludeMechanical = false;
|
||||
|
||||
public static function setExcludeMechanical(bool $flag): void
|
||||
{
|
||||
self::$excludeMechanical = $flag;
|
||||
}
|
||||
|
||||
public static function shouldExcludeMechanical(): bool
|
||||
{
|
||||
return self::$excludeMechanical;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
namespace App\DevExtreme;
|
||||
class Utils {
|
||||
private static $NULL_VAL = "NULL";
|
||||
private static $FORBIDDEN_CHARACTERS = array(
|
||||
"`", "\"", "'", "~", "!", "@", "#", "\$",
|
||||
"%", "=", "[", "]", "\\", "/" , "|", "^",
|
||||
"&", "*", "(", ")", "+", "<", ">", ",", "{",
|
||||
"}", "?", ":", ";", "\r", "\n"
|
||||
);
|
||||
public static function StringToNumber($str) {
|
||||
$currentLocale = localeconv();
|
||||
$decimalPoint = $currentLocale["decimal_point"];
|
||||
$result = strpos($str, $decimalPoint) === false ? intval($str) : floatval($str);
|
||||
return $result;
|
||||
}
|
||||
public static function EscapeExpressionValues($mySql, &$expression = NULL) {
|
||||
if (isset($expression)) {
|
||||
if (is_string($expression)) {
|
||||
$expression = $mySql->real_escape_string($expression);
|
||||
}
|
||||
else if (is_array($expression)) {
|
||||
foreach ($expression as &$arr_value) {
|
||||
self::EscapeExpressionValues($mySql, $arr_value);
|
||||
}
|
||||
unset($arr_value);
|
||||
}
|
||||
else if (gettype($expression) === "object") {
|
||||
foreach ($expression as $prop => $value) {
|
||||
self::EscapeExpressionValues($mySql, $expression->$prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static function QuoteStringValue($value, $isFieldName = true) {
|
||||
if (!$isFieldName) {
|
||||
$value = self::_ConvertDateTimeToMySQLValue($value);
|
||||
} else {
|
||||
$value = str_replace(self::$FORBIDDEN_CHARACTERS, "", $value);
|
||||
}
|
||||
$resultPattern = $isFieldName ? "`%s`" : (is_bool($value) || is_null($value) ? "%s" : "'%s'");
|
||||
$stringValue = is_bool($value) ? ($value ? "1" : "0") : (is_null($value) ? self::$NULL_VAL : strval($value));
|
||||
$result = sprintf($resultPattern, $stringValue);
|
||||
return $result;
|
||||
}
|
||||
public static function GetItemValueOrDefault($params, $key, $defaultValue = NULL) {
|
||||
return isset($params[$key]) ? $params[$key] : $defaultValue;
|
||||
}
|
||||
private static function _ConvertDatePartToISOValue($date) {
|
||||
$dateParts = explode("/", $date);
|
||||
return sprintf("%s-%s-%s", $dateParts[2], $dateParts[0], $dateParts[1]);
|
||||
}
|
||||
private static function _ConvertDateTimeToMySQLValue($strValue) {
|
||||
$result = $strValue;
|
||||
if (preg_match("/^\d{1,2}\/\d{1,2}\/\d{4}$/", $strValue) === 1) {
|
||||
$result = self::_ConvertDatePartToISOValue($strValue);
|
||||
}
|
||||
else if (preg_match("/^\d{1,2}\/\d{1,2}\/\d{4} \d{2}:\d{2}:\d{2}\.\d{3}$/", $strValue) === 1) {
|
||||
$spacePos = strpos($strValue, " ");
|
||||
$datePart = substr($strValue, 0, $spacePos);
|
||||
$timePart = substr($strValue, $spacePos + 1);
|
||||
$result = sprintf("%s %s", self::_ConvertDatePartToISOValue($datePart), $timePart);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user