<?php
namespace App\Model;
use DateTime;
use Pimcore\Db;
use DOMDocument;
use SimpleXMLElement;
use Pimcore\Model\Asset;
use Doctrine\DBAL\Connection;
use Pimcore\Model\DataObject;
use Symfony\Component\Uid\UuidV4;
use Pimcore\Model\DataObject\Region;
use Pimcore\Model\DataObject\AlertType;
use Pimcore\Model\DataObject\EwsNotification;
use Symfony\Component\HttpFoundation\Request;
use Pimcore\Model\DataObject\FetchSentEwsEmail;
use App\C2IntegrationBundle\Service\C2Service;
use Pimcore\Model\Asset\MetaData\ClassDefinition\Data\DataObject as DataDataObject;
use Pimcore\Model\DataObject\EwsAndReportUserGroup;
use App\Model\UserModel;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\Exception\ProcessFailedException;
class EwsNotificationModel
{
public $c2Service;
private $userModel;
function __construct()
{
$this->c2Service = new C2Service();
$this->userModel = new UserModel();
}
public function createNotification($request, $params, $userInterface, $translator): array
{
$result = [];
// try {
$regionId = $params['regionId'] ?? null;
$governorateIds = $params['governateIds'] ?? null;
$municipalities = $params['municipalityIds'] ?? null;
$ewsOtherLocationIds = $params['ewsOtherLocationIds'] ?? null;
$alertActionId = $params['alertActionId'] ?? null;
$alertTypeId = $params['alertTypeId'] ?? null;
$weatherPhenomenonId = $params['weatherPhenomenonId'] ?? null;
$coordinates = json_encode($params['coordinates'] ?? []);
$message = $params['message'] ?? [];
$alertHazardId = $params['alertHazardId'] ?? null;
$otherLocationId = $params['otherLocationId'] ?? null;
$enableTwitterNotification = $params['enableTwitterNotification'] ?? false;
$enableSMSNotification = $params['enableSMSNotification'] ?? false;
$enableEmailNotification = $params['enableEmailNotification'] ?? false;
$x_post = $params['x_post'] ?? "";
$previewText = isset($params['previewText']) ? $params['previewText'] : false;
$ewsNotification = new DataObject\EwsNotification();
$ewsNotification->setParent(DataObject\Service::createFolderByPath('/Notification/EWSNotification'));
$ewsNotification->setKey(md5($coordinates . $regionId . $governorateIds) . '-' . time());
$ewsNotification->setGuid(\App\Lib\Utility::getUUID()->toRfc4122());
if (isset($params['startDate'])) {
$startTime = $params['startTime'] ?? '00:00:00';
$fromDate = $params['startDate'] . ' ' . $startTime;
$ewsNotification->setStartDate(\Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $fromDate));
}
if (isset($params['endDate'])) {
$endTime = $params['endTime'] ?? '00:00:00';
$endDate = $params['endDate'] . ' ' . $endTime;
$ewsNotification->setEndDate(\Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $endDate));
}
if (isset($message['en'])) {
$ewsNotification->setMessage($message['en'], 'en');
}
if (isset($message['ar'])) {
$ewsNotification->setMessage($message['ar'], 'ar');
}
if (!empty($regionId)) {
$regionObj = DataObject\Region::getByRegionId($regionId, 1);
if (!empty($regionObj)) {
$ewsNotification->setRegion($regionObj);
if ($governorateIds) {
$governorateIdArr = explode(",", $governorateIds);
if ($governorateIdArr) {
$applyGovernates = [];
foreach ($governorateIdArr as $id) {
if(!empty($id)){
$applyGovernates[] = \Pimcore\Model\DataObject\Governorate::getByGovernoteId($id, true);
if (!empty(array_unique($applyGovernates))) {
$ewsNotification->setGovernorate(array_unique($applyGovernates));
}
}
}
}
if ($municipalities) {
$municipalitiesIdArr = explode(",", $municipalities);
if ($municipalitiesIdArr) {
$applyMunicipalities = [];
foreach ($municipalitiesIdArr as $id) {
$applyMunicipalities[] = \Pimcore\Model\DataObject\Municipality::getByMunicipalityid($id, true);
if (!empty(array_unique($applyMunicipalities))) {
$ewsNotification->setMunicipality(array_unique($applyMunicipalities));
}
}
}
}
} else {
$ewsNotification->setGovernorate($this->governorateByRegion($regionObj->getId()));
}
}
}
if ($ewsOtherLocationIds) {
$ewsOtherLocationIdArr = explode(",", $ewsOtherLocationIds);
if ($ewsOtherLocationIdArr) {
$applyOtherGovernates = [];
foreach ($ewsOtherLocationIdArr as $id) {
$applyOtherGovernates[] = \Pimcore\Model\DataObject\EwsOtherLocation::getByGovernoteId($id, true);
if (!empty(array_unique($applyOtherGovernates))) {
$ewsNotification->setEwsOtherLocations(array_unique($applyOtherGovernates));
}
}
}
}
if (!empty($alertHazardId)) {
$alertHazardArr = explode(",", $alertHazardId);
if ($alertHazardArr) {
$alertHazardArrRequest = [];
foreach ($alertHazardArr as $alertHazardId) {
$weatherPhenomenonAffect = DataObject\AlertHazard::getByAlertHazardId($alertHazardId, 1);
if ($weatherPhenomenonAffect) {
$alertHazardArrRequest[] = $weatherPhenomenonAffect;
}
}
$ewsNotification->setAlertHazard($alertHazardArrRequest);
}
}
if (!empty($alertTypeId)) {
$alertType = DataObject\AlertType::getByAlertTypeId($alertTypeId, 1);
$ewsNotification->setAlertType($alertType);
}
if (!empty($alertActionId)) {
$alertActionArr = explode(",", $alertActionId);
if ($alertActionArr) {
$alertActionArrRequest = [];
foreach ($alertActionArr as $alertActionId) {
$alertAction = DataObject\AlertAction::getByAlertActionId($alertActionId, 1);
if ($alertAction) {
$alertActionArrRequest[] = $alertAction;
}
}
$ewsNotification->setAlertAction($alertActionArrRequest);
}
}
if (!empty($otherLocationId)) {
$otherLocationArr = explode(",", $otherLocationId);
if ($otherLocationArr) {
$otherLocationArrRequest = [];
foreach ($otherLocationArr as $otherLocationId) {
$otherLocation = DataObject\OtherLocation::getByOtherLocationId($otherLocationId, 1);
if ($otherLocation) {
$otherLocationArrRequest[] = $otherLocation;
}
}
$ewsNotification->setOtherLocations($otherLocationArrRequest);
}
}
if (!empty($weatherPhenomenonId)) {
$alertStatus = DataObject\AlertStatus::getByAlertStatusId($weatherPhenomenonId, true);
$ewsNotification->setAlertStatus($alertStatus);
}
$ewsNotification->setCoordinates($coordinates);
$addressComponents = $params['address_components'] ?? [];
$this->addAddressComponentsFieldCollection($addressComponents, $ewsNotification);
if (!empty($params['file'])) {
$asset = $this->createAsset($params['file'], time() . $params['filename']);
if ($asset) {
$ewsNotification->setAttachment($asset);
}
}
if (!empty($params['x_img'])) {
$asset = $this->createAsset($params['x_img'], time() . "EWSTwitterImages.png");
if ($asset) {
$ewsNotification->setXAttachment($asset);
}
}
$ewsNotification->setXPost($x_post);
$ewsNotification->setEnableTwitterNotification($enableTwitterNotification);
$ewsNotification->setEnableSMSNotification($enableSMSNotification);
$ewsNotification->setEnableEmailNotification($enableEmailNotification);
$ewsNotification->setUser($userInterface);
$ewsNotification->setEditor($userInterface);
$ewsNotification->setPublished(false);
$ewsNotification->setPreviewText($previewText);
//$ewsNotification->save(["versionNote" => "Update"]);
//set ews search Id
$currentDate = new \DateTime();
$formattedDate = $currentDate->format('dmY') . '-' . $ewsNotification->getId();
$searchIdEn = 'Early Warning System | ' . $formattedDate . ' | ' . ucfirst($ewsNotification->getAlertType()?->getColor()) . ' Alert | ' . $ewsNotification->getWeatherPhenomenon()?->getTitle("en");
$searchIdAr = $translator->trans('Early Warning System', [], null, "ar") . ' | ' . $formattedDate . ' | ' . $translator->trans(ucfirst($ewsNotification->getAlertType()?->getColor()) . ' Alert', [], null, "ar") . ' | ' . $ewsNotification->getWeatherPhenomenon()?->getTitle("ar");
$ewsNotification->setEwsSearchId($searchIdEn, "en");
$ewsNotification->setEwsSearchId($searchIdAr, "ar");
//$ewsNotification->save(["versionNote" => "Update"]);
$ewsNotification->save();
return ['success' => true, 'message' => $translator->trans('ews_notification_added_successifully'), "notification_id" => $ewsNotification->getId()];
// } catch (\Exception $ex) {
// $result = ['success' => false, 'message' => $ex->getMessage()];
// }
return $result;
}
public function updateNotification($request, $params, $userInterface, $translator, $userGroupIds, $isPublished, $emailService, $templating, $logger): array
{
$result = [];
// try {
$id = $params['id'] ?? null;
if (!$id) {
throw new \Exception("EWS id is required");
}
$regionId = $params['regionId'] ?? null;
$governorateIds = $params['governateIds'] ?? null;
$municipalities = $params['municipalityIds'] ?? null;
$ewsOtherLocationIds = $params['ewsOtherLocationIds'] ?? null;
$alertActionId = $params['alertActionId'] ?? null;
$alertTypeId = $params['alertTypeId'] ?? null;
$weatherPhenomenonId = $params['weatherPhenomenonId'] ?? null;
$coordinates = json_encode($params['coordinates'] ?? []);
$message = $params['message'] ?? [];
$alertHazardId = $params['alertHazardId'] ?? null;
$enableTwitterNotification = $params['enableTwitterNotification'] ?? false;
$enableSMSNotification = $params['enableSMSNotification'] ?? false;
$enableEmailNotification = $params['enableEmailNotification'] ?? false;
$previewText = isset($params['previewText']) ? $params['previewText'] : false;
$ewsNotification = \Pimcore\Model\DataObject::getById($id);
if (!$ewsNotification instanceof \Pimcore\Model\DataObject\EwsNotification) {
// throw new \Exception("Ews notification not found");
return ['success' => false, 'message' => $translator->trans('ews_notification_not_found')];
}
if (isset($params['startDate'])) {
$startTime = $params['startTime'] ?? '00:00:00';
$fromDate = $params['startDate'] . ' ' . $startTime;
$ewsNotification->setStartDate(\Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $fromDate));
}
if (isset($params['endDate'])) {
$endTime = $params['endTime'] ?? '00:00:00';
$endDate = $params['endDate'] . ' ' . $endTime;
$ewsNotification->setEndDate(\Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $endDate));
}
if (isset($message['en'])) {
$ewsNotification->setMessage($message['en'], 'en');
}
if (isset($message['ar'])) {
$ewsNotification->setMessage($message['ar'], 'ar');
}
if (!empty($regionId)) {
$regionObj = DataObject\Region::getByRegionId($regionId, 1);
if (!empty($regionObj)) {
$ewsNotification->setRegion($regionObj);
if ($governorateIds) {
$governorateIdArr = explode(",", $governorateIds);
if ($governorateIdArr) {
$applyGovernates = [];
foreach ($governorateIdArr as $id) {
if(!empty($id)){
$applyGovernates[] = \Pimcore\Model\DataObject\Governorate::getByGovernoteId($id, true);
if (!empty(array_unique($applyGovernates))) {
$ewsNotification->setGovernorate(array_unique($applyGovernates));
}
}
}
}
if ($municipalities) {
$municipalitiesIdArr = explode(",", $municipalities);
if ($municipalitiesIdArr) {
$applyMunicipalities = [];
foreach ($municipalitiesIdArr as $id) {
$applyMunicipalities[] = \Pimcore\Model\DataObject\Municipality::getByMunicipalityid($id, true);
if (!empty(array_unique($applyMunicipalities))) {
$ewsNotification->setMunicipality(array_unique($applyMunicipalities));
}
}
}
}
} else {
$ewsNotification->setGovernorate($this->governorateByRegion($regionObj->getId()));
}
}
}
if ($ewsOtherLocationIds) {
$ewsOtherLocationIdArr = explode(",", $ewsOtherLocationIds);
if ($ewsOtherLocationIdArr) {
$applyOtherGovernates = [];
foreach ($ewsOtherLocationIdArr as $id) {
$applyOtherGovernates[] = \Pimcore\Model\DataObject\EwsOtherLocation::getByGovernoteId($id, true);
if (!empty(array_unique($applyOtherGovernates))) {
$ewsNotification->setEwsOtherLocations(array_unique($applyOtherGovernates));
}
}
}
}
if (!empty($alertTypeId)) {
$alertType = DataObject\AlertType::getByAlertTypeId($alertTypeId, 1);
$ewsNotification->setAlertType($alertType);
}
if (!empty($alertActionId)) {
$alertActionArr = explode(",", $alertActionId);
if ($alertActionArr) {
$alertActionArrRequest = [];
foreach ($alertActionArr as $alertActionId) {
$alertAction = DataObject\AlertAction::getByAlertActionId($alertActionId, 1);
if ($alertAction) {
$alertActionArrRequest[] = $alertAction;
}
}
$ewsNotification->setAlertAction($alertActionArrRequest);
}
}
if (!empty($weatherPhenomenonId)) {
$alertStatus = DataObject\AlertStatus::getByAlertStatusId($weatherPhenomenonId, true);
$ewsNotification->setAlertStatus($alertStatus);
}
if (!empty($alertHazardId)) {
$alertHazardArr = explode(",", $alertHazardId);
if ($alertHazardArr) {
$alertHazardArrRequest = [];
foreach ($alertHazardArr as $alertHazardId) {
$weatherPhenomenonAffect = DataObject\AlertHazard::getByAlertHazardId($alertHazardId, 1);
if ($weatherPhenomenonAffect) {
$alertHazardArrRequest[] = $weatherPhenomenonAffect;
}
}
$ewsNotification->setAlertHazard($alertHazardArrRequest);
}
}
$ewsNotification->setCoordinates($coordinates);
$addressComponents = $params['address_components'] ?? [];
$this->addAddressComponentsFieldCollection($addressComponents, $ewsNotification);
if (!empty($params['file'])) {
$asset = $this->createAsset($params['file'], time() . $params['filename']);
if ($asset) {
$ewsNotification->setAttachment($asset);
}
}
if (!empty($params['x_img'])) {
$asset = $this->createAsset($params['x_img'], time() . "EWSTwitterImages.png");
if ($asset) {
$ewsNotification->setXAttachment($asset);
}
}
if (!empty($params['x_post'])) {
$ewsNotification->setXPost($params['x_post']);
}
$ewsNotification->setEnableTwitterNotification($enableTwitterNotification);
$ewsNotification->setEnableSMSNotification($enableSMSNotification);
$ewsNotification->setEnableEmailNotification($enableEmailNotification);
$ewsNotification->setPreviewText($previewText);
//$ewsNotification->setPublished(true);
$ewsNotification->setUser($userInterface);
$ewsNotification->setEditor($userInterface);
//set ews search Id
$currentDate = new \DateTime();
$formattedDate = $currentDate->format('dmY') . '-' . $ewsNotification->getId();
$searchIdEn = 'Early Warning System | ' . $formattedDate . ' | ' . ucfirst($ewsNotification->getAlertType()?->getColor()) . ' Alert | ' . $ewsNotification->getWeatherPhenomenon()?->getTitle("en");
$searchIdAr = $translator->trans('Early Warning System', [], null, "ar") . ' | ' . $formattedDate . ' | ' . $translator->trans(ucfirst($ewsNotification->getAlertType()?->getColor()) . ' Alert', [], null, "ar") . ' | ' . $ewsNotification->getWeatherPhenomenon()?->getTitle("ar");
$ewsNotification->setEwsSearchId($searchIdEn, "en");
$ewsNotification->setEwsSearchId($searchIdAr, "ar");
$ewsNotification->save(["versionNote" => "Update"]);
if ($isPublished) {
// send email
// Ensure you use 'php' to execute the command.
$jsonUserGroupIds = json_encode($userGroupIds);
$process = new Process(['php', 'bin/console', 'app:send-early-warning-alert-email', '--alertId=' . $ewsNotification->getId(), '--userGroupIds=' . $jsonUserGroupIds]);
$process->setWorkingDirectory(PIMCORE_PROJECT_ROOT);
try {
$process->mustRun();
$result['success'] = true;
$logger->info("update EwsNotification command executed successfully: " . $process->getOutput());
$result['message'] = $process->getOutput();
} catch (ProcessFailedException $exception) {
$logger->error("update EwsNotification command failed: " . $exception->getMessage());
return ['success' => false, 'message' => $exception->getMessage()];
}
}
return ['success' => true, 'message' => $translator->trans('ews_notification_updated_successifully'), "notification_id" => $ewsNotification->getId()];
// } catch (\Exception $ex) {
// $result = ['success' => false, 'message' => $ex->getMessage()];
// }
return $result;
}
public function governorateByRegion($regionId)
{
$governorateArr = [];
$governorateList = new DataObject\Governorate\Listing();
$governorateList->setCondition('regionId__id = ?', $regionId);
$governorateList->load();
if (!empty($governorateList)) {
foreach ($governorateList as $governorate) {
array_push($governorateArr, $governorate);
}
}
return $governorateArr;
}
public function notificationListing($params, $paginator, $translator): array
{
$response = [];
// try {
$pageSize = isset($params['page_size']) ? $params['page_size'] : LIMIT_PER_PAGE;
$page = isset($params['page']) ? $params['page'] : 1;
$notificationList = new DataObject\EwsNotification\Listing();
$notificationList->setUnpublished(true);
if ($params['unpublished'] == false) {
$notificationList->filterByPublished(true);
} else {
$notificationList->filterByPublished(false);
}
if (isset($params['region']) && !empty($params['region'])) {
$regionSql = null;
$alertRegion = \Pimcore\Model\DataObject\Region::getByRegionId($params['region'], true);
if ($alertRegion) {
$regionSql .= "region__id = " . $alertRegion->getId() . " OR ";
}
$notificationList->addConditionParam("(" . substr($regionSql, 0, -3) . ")");
}
if (isset($params['status']) && !empty($params['status'])) {
$notificationList->addConditionParam("status IN (?)", [$params['status']]);
}
if (isset($params['addressCmp']) && !empty($params['addressCmp'])) {
//TODO
}
if (isset($params['start_date']) && !empty($params['start_date']) && isset($params['end_date']) && !empty($params['end_date'])) {
$notificationList->filterByStartDate(strtotime($params['start_date']), ">=");
$notificationList->filterByEndDate(strtotime($params['end_date']), "<=");
}
if (isset($params['fromDate']) && isset($params['toDate']) && !empty($params['fromDate']) && !empty($params['toDate'])) {
$fromDate = new \DateTime($params['fromDate']);
$toDate = new \DateTime($params['toDate']);
$fromDateStr = strtotime($fromDate->format('Y-m-d H:i:s'));
$toDateStr = strtotime($toDate->format('Y-m-d') . ' 23:59:59');
$notificationList->addConditionParam(
"(o_creationDate >= ? AND o_creationDate <= ?)",
[$fromDateStr, $toDateStr]
);
}
// Set default sorting
$notificationList->setOrderKey("o_creationDate");
$notificationList->setOrder("desc");
// Load all data for proper sorting
$notificationList->load();
if ($notificationList) {
// Create structured data for sorting (same approach as searchEwsNotification)
$sortedData = [];
foreach ($notificationList as $notification) {
$regionEn = $notification->getRegion() ? $notification->getRegion()->getName("en") : '';
$startDate = $notification->getStartDate() ? $notification->getStartDate()->format('Y-m-d H:i:s') : '';
$endDate = $notification->getEndDate() ? $notification->getEndDate()->format('Y-m-d H:i:s') : '';
$alertStatusEn = !empty($notification->getAlertStatus()) ? $notification->getAlertStatus()->getName("en") : "";
$creationDate = $notification->getCreationDate();
$title = $notification->getStartDate() ? $notification->getStartDate()->format("dmY") . '-' . $notification->getId() : '';
$alertTypeEn = $notification->getAlertType() ? ucwords($notification->getAlertType()->getColor()) : '';
$fromDate = $notification->getStartDate() ? $notification->getStartDate()->format('Y-m-d H:i:s') : '';
$toDate = $notification->getEndDate() ? $notification->getEndDate()->format('Y-m-d H:i:s') : '';
$created_at = $notification->getCreationDate() ? date("Y-m-d H:i:s", $notification->getCreationDate()) : '';
$sortedData[] = [
'notification' => $notification,
'region' => $regionEn,
'alertStatus' => $alertStatusEn,
'startDate' => $startDate,
'endDate' => $endDate,
'creationDate' => $creationDate,
'title' => $title,
'alertType' => $alertTypeEn,
'fromDate' => $fromDate,
'toDate' => $toDate,
'created_at' => $created_at
];
}
// Apply sorting to the complete dataset
// Support multiple parameter names for sorting
$orderKey = $params['orderkey'] ?? $params['orderKey'] ?? $params['sortBy'] ?? null;
$orderDirection = isset($params['order']) ? strtolower($params['order']) : 'desc';
if ($orderKey && in_array($orderKey, ['title', 'alertType', 'fromDate', 'toDate', 'region', 'alertStatus', 'created_at'])) {
usort($sortedData, function($a, $b) use ($orderKey, $orderDirection) {
$valueA = $a[$orderKey] ?? '';
$valueB = $b[$orderKey] ?? '';
// Handle null/empty values
if (empty($valueA) && !empty($valueB)) {
return $orderDirection === 'asc' ? -1 : 1;
}
if (!empty($valueA) && empty($valueB)) {
return $orderDirection === 'asc' ? 1 : -1;
}
if (empty($valueA) && empty($valueB)) {
return 0;
}
// For date fields, convert to timestamp for proper comparison
if (in_array($orderKey, ['fromDate', 'toDate', 'created_at'])) {
$timestampA = strtotime($valueA);
$timestampB = strtotime($valueB);
if ($timestampA === false || $timestampB === false) {
// If date parsing fails, fall back to string comparison
$comparison = strcasecmp($valueA, $valueB);
} else {
$comparison = $timestampA <=> $timestampB;
}
} else {
// For text fields, use case-insensitive string comparison
$comparison = strcasecmp($valueA, $valueB);
}
return $orderDirection === 'asc' ? $comparison : -$comparison;
});
}
// Extract the sorted notifications
$sortedNotifications = array_map(function ($item) {
return $item['notification'];
}, $sortedData);
// Convert to response format
foreach ($sortedNotifications as $notification) {
$response[] = $this->createNotificationFormat($notification, $translator);
}
}
// If no paginator, return all sorted data
if ($paginator == null) {
return ["success" => TRUE, "data" => $response];
}
$paginator = $paginator->paginate(
$response,
$page,
$pageSize
);
return ["success" => TRUE, "data" => $paginator, "paginationVariables" => $paginator->getPaginationData()];
// return $response;
// } catch (\Exception $ex) {
// $result = ["success" => false, "message" => $ex->getMessage()];
// }
// return $result;
}
public function capAlertNotificationListingxml($request, $params, $lang, $translator)
{
try {
$notificationList = new DataObject\EwsNotification\Listing();
// Get the timezone for date operations
$timezone = new \DateTimeZone(TIMEZONE);
// Filter by pubDate if provided (format: d-m-Y, e.g., 25-12-2025)
if (isset($params['pubDate']) && !empty($params['pubDate'])) {
$pubDateStr = $params['pubDate'];
// Parse the date from d-m-Y format
$pubDate = \DateTime::createFromFormat('d-m-Y', $pubDateStr, $timezone);
if ($pubDate === false) {
// Try alternative format Y-m-d
$pubDate = \DateTime::createFromFormat('Y-m-d', $pubDateStr, $timezone);
}
if ($pubDate !== false) {
// Set time to start of day (00:00:00)
$pubDate->setTime(0, 0, 0);
$startTimestamp = $pubDate->getTimestamp();
// Set time to end of day (23:59:59)
$pubDateEnd = clone $pubDate;
$pubDateEnd->setTime(23, 59, 59);
$endTimestamp = $pubDateEnd->getTimestamp();
// Filter notifications where startDate falls within the specified date
// Use filterByStartDate for >= start of day
$notificationList->filterByStartDate($startTimestamp, ">=");
// Add condition for <= end of day using addConditionParam
$notificationList->addConditionParam("startDate <= ?", [$endTimestamp]);
}
}else{
$notificationList->setCondition("endDate > ?", [time()]);
}
$notificationList->setOrderKey("oo_id");
$notificationList->setOrder("desc");
// Get the current date as a DateTime object
$currentDate = new \DateTime('now', $timezone);
// Set the condition to filter for notifications where endDate is greater than the current date
// Loop through the notifications to find the last updated date
// Initialize $lastUpdatedDate with current date as default
$lastUpdatedDate = $currentDate;
foreach ($notificationList as $notification) {
$notificationUpdatedDate = $notification->getEndDate()->setTimezone($timezone);
if ($notificationUpdatedDate > $lastUpdatedDate) {
$lastUpdatedDate = $notificationUpdatedDate;
}
}
// Create an empty RSS XML structure
// $rss = new SimpleXMLElement('<rss version="2.0"/>');
$rss = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"/>');
// Create the <channel> element
$channel = $rss->addChild('channel');
// Add elements inside <channel>
$channel->addChild('title', $translator->trans("Early Warning System from National Center of Meteorology, Saudi Arabia"));
$channel->addChild('link', $_ENV['BASE_URL_DEMO_AJWAA_API'] . '/' . $lang . '/cap-alerts');
$channel->addChild('description', $translator->trans("Early Warning System from National Center of Meteorology, Saudi Arabia"));
$channel->addChild('language', $lang);
$channel->addChild('copyright', $translator->trans("Copyright (c) ".date('Y').", NCM. Licensed under Creative Commons BY 4.0"));
$channel->addChild('pubDate', $lastUpdatedDate->format('D, d M Y H:i:s \G\M\T'));
// Create the <image> element
$image = $channel->addChild('image');
$image->addChild('title', $translator->trans("Early Warning System from National Center of Meteorology, Saudi Arabia"));
$image->addChild('url', $_ENV['BASE_URL_DEMO_AJWAA_API'] . '/assets/images/logo2.3.png');
$image->addChild('link', $_ENV['BASE_URL_DEMO_AJWAA_API'] . '/' . $lang . '/cap-alerts');
// Create multiple <alert> elements and add them to the <alerts> element
// Create child elements and add them to the alert
foreach ($notificationList as $notification) { // Create two <alert> elements as an example
$hazardNames = "";
if (!empty($notification->getAlertHazard())) {
$hazardNamesArr = [];
foreach ($notification->getAlertHazard() as $hazard) {
$hazardNamesArr[] = $hazard->getName($lang);
}
$hazardNames .= implode(", ", $hazardNamesArr);
}
$governorateNames = "";
$governorateCoordinates = "";
$governorateNamesArr = [];
if ($notification->getGovernorate() && !empty($notification->getGovernorate())) {
$governorateCoordinatesArr = [];
foreach ($notification->getGovernorate() as $governorate) {
$governorateNamesArr[] = $governorate->getName($lang);
$governorateCoordinatesArr[] = $governorate->getLatitude() . "," . $governorate->getLongitude();
}
$governorateCoordinates .= implode(" ", $governorateCoordinatesArr);
// Format governorates with "and" before the last one
if (count($governorateNamesArr) > 1) {
$lastGovernorate = array_pop($governorateNamesArr);
$governorateNames = implode(" - ", $governorateNamesArr) . " - " . $lastGovernorate;
} else {
$governorateNames = $governorateNamesArr[0];
}
}
// Get region and alert status names
$regionName = $notification->getRegion() ? $notification->getRegion()->getName($lang) : $translator->trans("UNKNOWN");
$alertStatusName = !empty($notification->getAlertStatus()) ? $notification->getAlertStatus()->getName($lang) : $translator->trans("UNKNOWN");
// Format title
$title = $alertStatusName . ", " . $regionName;
// Format dates in GMT format for description
$startDateGMT = !empty($notification->getStartDate()) ? $notification->getStartDate()->setTimezone(new \DateTimeZone('GMT'))->format('D, d M Y H:i:s \G\M\T') : $translator->trans("UNKNOWN");
$endDateGMT = !empty($notification->getEndDate()) ? $notification->getEndDate()->setTimezone(new \DateTimeZone('GMT'))->format('D, d M Y H:i:s \G\M\T') : $translator->trans("UNKNOWN");
// Format description: "{Hazard names} From: {startDate GMT} To: {endDate GMT}, {Location}"
$descriptionParts = [];
// if (!empty($hazardNames)) {
// $descriptionParts[] = $hazardNames;
// }
$descriptionParts[] = $alertStatusName . " " . $translator->trans("From") . ": " . $startDateGMT . " " . $translator->trans("To") . ": " . $endDateGMT;
if (!empty($governorateNames)) {
$descriptionParts[] = ", " . $governorateNames;
}
$description = implode(" ", $descriptionParts);
// Create one or more <item> elements
$item = $channel->addChild('item');
$item->addChild('guid', "{" . $notification->getGuid() . "}");
$item->addChild('title', $title);
$item->addChild('link', $_ENV['BASE_URL_DEMO_AJWAA_API'] . '/cap/' . $lang . '/alerts/' . $notification->getGuid() . '.xml');
$item->addChild('description',$description);
$item->addChild('author', AUTHOR);
$item->addChild('pubDate', $notification->getLastModifiedDate()->setTimeZone(new \DateTimeZone('GMT'))->format('D, d M Y H:i:s \G\M\T'));
}
// Create additional <item> elements as needed
// Format the XML for output
$dom = dom_import_simplexml($rss)->ownerDocument;
$dom->formatOutput = true;
// Save the XML to a file
$xmlString = $dom->saveXML();
// Set the Content-Type header to specify that the response is XML
header("Content-Type: application/xml");
// Save the XML to a file or output it
$xmlString = $rss->saveXML();
print $xmlString;
exit;
return $xmlString;
} catch (\Exception $ex) {
$result = ["success" => false, "message" => $ex->getMessage()];
}
return $result;
}
public function capAlertNotificationDetailxml($guid, $lang, $translator)
{
$response = [];
$timezone = new \DateTimeZone(TIMEZONE);
try {
$notification = \Pimcore\Model\DataObject\EwsNotification::getByGuid($guid, true);
if (empty($notification)) {
throw new \Exception('Notification not found.');
}
$doc = new DomDocument('1.0', 'UTF-8');
// Create the root element
$alert = $doc->createElement('alert');
$alert->setAttribute('xmlns', 'urn:oasis:names:tc:emergency:cap:1.2');
$alert->setAttribute('xmlns:xsl', 'http://www.w3.org/1999/XSL/Transform');
$alert->setAttribute('xmlns:ds', 'http://www.w3.org/2000/09/xmldsig#');
$doc->appendChild($alert);
// Create child elements and add them to the alert
$identifier = $doc->createElement('identifier', $notification->getGuid()); //uuid
$sender = $doc->createElement('sender', $translator->trans('NCM'));
$sent = $doc->createElement('sent', $notification->getStartDate()->setTimezone($timezone)->format('Y-m-d\TH:i:sP'));
$status = $doc->createElement('status', 'Actual');
$msgType = $doc->createElement('msgType', 'Alert');
$scope = $doc->createElement('scope', 'Public');
$alert->appendChild($identifier);
$alert->appendChild($sender);
$alert->appendChild($sent);
$alert->appendChild($status);
$alert->appendChild($msgType);
$alert->appendChild($scope);
// Create the <info> element and add it to the alert
$info = $doc->createElement('info');
$alert->appendChild($info);
// Create child elements for the <info> element
$category = $doc->createElement('category','Met');
$event = $doc->createElement('event', $notification->getAlertStatus() ? $notification->getAlertStatus()->getName($lang) : $translator->trans('UNKNOWN')); //high rain
$responseType = $doc->createElement('responseType', 'None');
$effective = $doc->createElement('effective', $notification->getStartDate()->setTimezone($timezone)->format('Y-m-d\TH:i:sP'));
// Determine CAP urgency, severity, and certainty based on alert type and event
$eventName = $notification->getAlertStatus() ? strtolower($notification->getAlertStatus()->getName('en')) : '';
$alertTypeColor = $notification->getAlertType() ? strtoupper($notification->getAlertType()->getColor() ?? '') : '';
// Determine urgency based on alert type and event severity
// Immediate: Life-threatening, requires immediate action (RED alerts, tornadoes, etc.)
// Expected: Forecasted events that will occur (most weather alerts)
// Past: Events that have already occurred
// Future: Long-term forecasts
$urgency = 'Expected'; // Default for most weather alerts
if ($alertTypeColor === 'RED' || stripos($eventName, 'tornado') !== false || stripos($eventName, 'extreme') !== false) {
$urgency = 'Immediate';
}
// Determine severity based on alert type color and event
// Extreme: Widespread destruction
// Severe: Significant threat to life/property
// Moderate: Some threat
// Minor: Minimal threat
// Unknown: Severity unknown
$severity = 'Moderate'; // Default
if ($alertTypeColor === 'RED') {
$severity = 'Extreme';
} elseif ($alertTypeColor === 'ORANGE') {
$severity = 'Severe';
} elseif ($alertTypeColor === 'YELLOW') {
$severity = 'Moderate';
} elseif ($alertTypeColor === 'GREEN' || stripos($eventName, 'light') !== false || stripos($eventName, 'minor') !== false) {
$severity = 'Minor';
}
// Certainty: Observed (happening now), Likely (will occur), Possible (may occur), Unlikely, Unknown
$certainty = 'Possible'; // Default - assume observed for active alerts
$urgencyElement = $doc->createElement('urgency', $urgency);
$severityElement = $doc->createElement('severity', $severity);
$certaintyElement = $doc->createElement('certainty', $certainty);
// Remove eventCode element - SAME codes are US-specific and not applicable
// If eventCode is needed in future, use WMO codes instead:
// $eventCode = $doc->createElement('eventCode');
// $eventCodeValueName = $doc->createElement('valueName', 'WMO');
// $eventCodeValueText = $doc->createElement('value', 'FOG'); // Example WMO code
// $eventCode->appendChild($eventCodeValueName);
// $eventCode->appendChild($eventCodeValueText);
// Fix: onset should use startDate (when the event begins), not endDate
$onsetDate = $notification->getStartDate() ? $notification->getStartDate()->setTimezone($timezone) : null;
if (!$onsetDate) {
// Fallback to current time if startDate is not available
$onsetDate = new \DateTime('now', $timezone);
}
$onset = $doc->createElement('onset', $onsetDate->format('Y-m-d\TH:i:sP'));
// Fix: expires must be after onset (use endDate, ensure it's after startDate)
$expiresDate = $notification->getEndDate() ? $notification->getEndDate()->setTimezone($timezone) : null;
if (!$expiresDate) {
// Fallback: if no endDate, set expires to 24 hours after onset
$expiresDate = clone $onsetDate;
$expiresDate->modify('+24 hours');
} else {
// Ensure expires is after onset (CAP requirement)
if ($expiresDate <= $onsetDate) {
// If expires equals or is before onset, add at least 1 hour
$expiresDate = clone $onsetDate;
$expiresDate->modify('+1 hour');
}
}
$expires = $doc->createElement('expires', $expiresDate->format('Y-m-d\TH:i:sP'));
$senderName = $doc->createElement('senderName', $translator->trans('NCM'));
$headline = $doc->createElement('headline', $notification->getAlertType()->getName($lang) . ', ' . $notification->getAlertStatus()->getName($lang));
// $headline = $doc->createElement(
// 'headline',
// $translator->trans('Early Warning Alert in') . ' ' .
// (
// $notification->getRegion()
// ? $notification->getRegion()->getName($lang)
// : $translator->trans('UNKNOWN')
// ) . ': ' .
// (
// $notification->getAlertStatus()
// ? $notification->getAlertStatus()->getName($lang)
// : $translator->trans('UNKNOWN')
// )
// );
$hazardNames = "";
if (!empty($notification->getAlertHazard())) {
$hazardNamesArr = [];
foreach ($notification->getAlertHazard() as $hazard) {
$hazardNamesArr[] = $hazard->getName($lang);
}
$hazardNames .= implode(", ", $hazardNamesArr);
}
$governorateNames = "";
$governorateCoordinates = "";
$governorateNamesArr = [];
if ($notification->getGovernorate() && !empty($notification->getGovernorate())) {
$governorateCoordinatesArr = [];
foreach ($notification->getGovernorate() as $governorate) {
$governorateNamesArr[] = $governorate->getName($lang);
$governorateCoordinatesArr[] = $governorate->getLatitude() . "," . $governorate->getLongitude();
}
// Format governorates with "و" for Arabic or "and" for English before the last one
if (count($governorateNamesArr) > 1) {
$lastGovernorate = array_pop($governorateNamesArr);
$andText = ($lang == 'ar') ? ' و ' : ', and ';
$governorateNames = implode(", ", $governorateNamesArr) . $andText . $lastGovernorate;
} else {
$governorateNames = $governorateNamesArr[0];
}
$governorateCoordinates .= implode(" ", $governorateCoordinatesArr);
}
// Get region and alert status names
$regionName = $notification->getRegion() ? $notification->getRegion()->getName($lang) : $translator->trans("UNKNOWN");
$alertStatusName = $notification->getAlertStatus() ? $notification->getAlertStatus()->getName($lang) : $translator->trans("UNKNOWN");
// Format dates
$startDateFormatted = !empty($notification->getStartDate()) ? $notification->getStartDate()->setTimezone($timezone)->format('d/m/Y H:i:s A') : $translator->trans("UNKNOWN");
$endDateFormatted = !empty($notification->getEndDate()) ? $notification->getEndDate()->setTimezone($timezone)->format("d/m/Y H:i:s A") : $translator->trans("UNKNOWN");
// Format description: Comma-separated list of hazard names (e.g., "Raised dust, Active winds,Near lack of horizontal visibility (1-3) km")
$descriptionText = !empty($hazardNames) ? $hazardNames : "";
$description = $doc->createElement('description', $notification->getAlertStatus()->getName($lang) . ' ' . $descriptionText);
// Create actionable instruction based on alert type and hazards (CAP compliance)
// Handle multiple hazards by checking all types and combining instructions
$instructionText = '';
if (!empty($hazardNames)) {
$instructions = [];
$hazardNamesLower = strtolower($hazardNames);
// Check for all hazard types and collect relevant instructions
// Priority hazards first
if (stripos($hazardNames, 'tornado') !== false || stripos($hazardNames, 'إعصار') !== false) {
$instructions[] = ($lang == 'ar')
? 'انتقل فوراً إلى أقرب ملجأ أو الطابق السفلي. تجنب النوافذ والمناطق المكشوفة.'
: 'Move immediately to the nearest shelter or basement. Avoid windows and exposed areas.';
}
if (stripos($hazardNames, 'rain') !== false || stripos($hazardNames, 'مطر') !== false ||
stripos($hazardNames, 'flood') !== false || stripos($hazardNames, 'فيضان') !== false ||
stripos($hazardNames, 'pooling') !== false || stripos($hazardNames, 'تجمع') !== false) {
$instructions[] = ($lang == 'ar')
? 'انتقل إلى أرض مرتفعة لتجنب الفيضانات. تجنب القيادة في المناطق المغمورة.'
: 'Move to higher ground to avoid flooding. Avoid driving through flooded areas.';
}
if (stripos($hazardNames, 'wave') !== false || stripos($hazardNames, 'موجة') !== false) {
$instructions[] = ($lang == 'ar')
? 'تجنب المناطق الساحلية والأنشطة البحرية. ابق بعيداً عن الشواطئ.'
: 'Avoid coastal areas and marine activities. Stay away from beaches.';
}
if (stripos($hazardNames, 'wind') !== false || stripos($hazardNames, 'رياح') !== false) {
$instructions[] = ($lang == 'ar')
? 'تجنب الخروج من المنزل وتأكد من إغلاق النوافذ والأبواب بإحكام. تجنب القيادة إذا أمكن.'
: 'Avoid going outside and ensure windows and doors are securely closed. Avoid driving if possible.';
}
if (stripos($hazardNames, 'thunder') !== false || stripos($hazardNames, 'رعد') !== false) {
$instructions[] = ($lang == 'ar')
? 'تجنب المناطق المكشوفة والبقاء في الداخل. تجنب استخدام الأجهزة الإلكترونية والمياه.'
: 'Avoid exposed areas and stay indoors. Avoid using electronic devices and water.';
}
if (stripos($hazardNames, 'hail') !== false || stripos($hazardNames, 'برد') !== false) {
$instructions[] = ($lang == 'ar')
? 'ابق في الداخل وتجنب النوافذ. إذا كنت في الخارج، ابحث عن مأوى فوري.'
: 'Stay indoors and avoid windows. If outside, seek immediate shelter.';
}
if (stripos($hazardNames, 'visibility') !== false || stripos($hazardNames, 'رؤية') !== false ||
stripos($hazardNames, 'fog') !== false || stripos($hazardNames, 'ضباب') !== false ||
stripos($hazardNames, 'low visibility') !== false || stripos($hazardNames, 'lack of horizontal visibility') !== false) {
$instructions[] = ($lang == 'ar')
? 'تجنب القيادة إلا للضرورة القصوى. إذا كنت تقود، استخدم الأضواء المنخفضة واتبع المسافة الآمنة.'
: 'Avoid driving except in emergencies. If driving, use low beams and maintain safe distance.';
}
if (stripos($hazardNames, 'snow') !== false || stripos($hazardNames, 'ثلج') !== false) {
$instructions[] = ($lang == 'ar')
? 'تجنب السفر غير الضروري. إذا كنت في الخارج، ارتدِ ملابس دافئة وتجنب الطرق الزلقة.'
: 'Avoid unnecessary travel. If outside, wear warm clothing and avoid slippery roads.';
}
if (stripos($hazardNames, 'frost') !== false || stripos($hazardNames, 'صقيع') !== false ||
(stripos($hazardNames, 'temperature') !== false && stripos($hazardNames, 'drop') !== false) ||
(stripos($hazardNames, 'درجة') !== false && stripos($hazardNames, 'انخفاض') !== false) ||
stripos($hazardNames, 'below zero') !== false) {
$instructions[] = ($lang == 'ar')
? 'احمِ نفسك من البرد الشديد. ارتدِ ملابس دافئة وتجنب التعرض الطويل للطقس البارد.'
: 'Protect yourself from extreme cold. Wear warm clothing and avoid prolonged exposure to cold weather.';
}
if ((stripos($hazardNames, 'rise') !== false && stripos($hazardNames, 'temperature') !== false) ||
(stripos($hazardNames, 'ارتفاع') !== false && stripos($hazardNames, 'درجة') !== false) ||
stripos($hazardNames, 'degrees Celsius') !== false || stripos($hazardNames, 'درجة مئوية') !== false) {
$instructions[] = ($lang == 'ar')
? 'احمِ نفسك من الحرارة الشديدة. ابق في أماكن مكيفة، اشرب الكثير من الماء، وتجنب الأنشطة الخارجية.'
: 'Protect yourself from extreme heat. Stay in air-conditioned areas, drink plenty of water, and avoid outdoor activities.';
}
// Combine all instructions or use default
if (!empty($instructions)) {
// Remove duplicates and combine with appropriate separator
$uniqueInstructions = array_unique($instructions);
$separator = ($lang == 'ar') ? ' ' : ' ';
$instructionText = implode($separator, $uniqueInstructions);
} else {
$instructionText = ($lang == 'ar')
? 'اتخذ الاحتياطات اللازمة واتبع التعليمات الرسمية. ابق في مكان آمن.'
: 'Take necessary precautions and follow official instructions. Stay in a safe place.';
}
} else {
// Default instruction if no specific hazards
$instructionText = ($lang == 'ar')
? 'اتخذ الاحتياطات اللازمة واتبع التعليمات الرسمية من المركز الوطني للأرصاد.'
: 'Take necessary precautions and follow official instructions from the National Center of Meteorology.';
}
$instruction = $doc->createElement('instruction', $instructionText);
$contact = $doc->createElement('contact', CONTACT);
// Create dynamic web URL using notification ID (CAP compliance - absolute HTTPS URL)
$web = $doc->createElement('web', htmlspecialchars($_ENV['NCM_PUBLIC_PORTAL_URL'] . $lang . '/early-warning/'.$notification->getAlertId(), ENT_XML1, 'UTF-8'));
$info->appendChild($category);
$info->appendChild($event);
$info->appendChild($responseType);
$info->appendChild($urgencyElement);
$info->appendChild($severityElement);
$info->appendChild($certaintyElement);
// eventCode removed - SAME codes are US-specific
$info->appendChild($effective);
$info->appendChild($onset);
$info->appendChild($expires);
$info->appendChild($senderName);
$info->appendChild($headline);
$info->appendChild($description);
$info->appendChild($instruction);
$info->appendChild($web);
$info->appendChild($contact);
// Get polygon coordinates from JSON lookup sheet - returns array of polygons per governorate
$governoratePolygons = [];
// Try to get polygons from the JSON lookup sheet first
if ($notification->getGovernorate() && !empty($notification->getGovernorate())) {
// Convert collection to array if needed
$governorates = $notification->getGovernorate();
if (is_object($governorates) && method_exists($governorates, 'getItems')) {
$governorates = $governorates->getItems();
} elseif (!is_array($governorates)) {
$governorates = iterator_to_array($governorates);
}
if (!empty($governorates)) {
$governoratePolygons = $this->getPolygonFromJsonSheet($governorates);
}
}
// Fallback to notification coordinates if JSON lookup didn't provide polygons
if (empty($governoratePolygons)) {
$coordinatesString = $notification->getCoordinates();
if (!empty($coordinatesString)) {
// Try to parse as JSON (GeoJSON format)
$coordinatesData = json_decode($coordinatesString, true);
if (json_last_error() === JSON_ERROR_NONE && is_array($coordinatesData)) {
// Handle GeoJSON format: coordinates can be in various structures
// [[[lng, lat], [lng, lat], ...]] for Polygon
// [[lng, lat], [lng, lat], ...] for LineString
// [lng, lat] for Point
$coordArray = [];
if (isset($coordinatesData['type']) && $coordinatesData['type'] === 'Polygon' && isset($coordinatesData['coordinates'])) {
// GeoJSON Polygon format
$coordArray = $coordinatesData['coordinates'][0] ?? [];
} elseif (isset($coordinatesData['type']) && $coordinatesData['type'] === 'LineString' && isset($coordinatesData['coordinates'])) {
// GeoJSON LineString format
$coordArray = $coordinatesData['coordinates'];
} elseif (is_array($coordinatesData) && isset($coordinatesData[0])) {
// Nested array format: [[[lng, lat], ...]] or [[lng, lat], ...]
if (is_array($coordinatesData[0]) && is_array($coordinatesData[0][0])) {
// [[[lng, lat], ...]] - take first ring
$coordArray = $coordinatesData[0];
} elseif (is_array($coordinatesData[0]) && count($coordinatesData[0]) >= 2 && is_numeric($coordinatesData[0][0])) {
// [[lng, lat], ...]
$coordArray = $coordinatesData;
}
}
// Process coordinate array
if (!empty($coordArray)) {
$polygon = '';
$firstCoordinate = null;
foreach ($coordArray as $coord) {
if (is_array($coord) && count($coord) >= 2) {
$lng = (float)$coord[0];
$lat = (float)$coord[1];
// CAP polygon format: "lat,lng lat,lng ..." (note: lat first, then lng)
// Format with 6 decimal places as per client requirement
$coordString = number_format($lat, 6, '.', '') . "," . number_format($lng, 6, '.', '');
if ($firstCoordinate === null) {
$firstCoordinate = $coordString;
}
$polygon .= $coordString . ' ';
}
}
// Remove the trailing space
$polygon = rtrim($polygon);
// Validate and ensure polygon is closed
if (!empty(trim($polygon)) && $firstCoordinate !== null) {
$polygonTrimmed = trim($polygon);
$coords = explode(' ', $polygonTrimmed);
$uniqueCoords = array_unique($coords);
// Check if we have at least 4 distinct points
if (count($uniqueCoords) >= 4) {
// Ensure polygon is closed (first coordinate = last coordinate) - CAP compliance requirement
$lastCoordinate = end($coords);
if ($lastCoordinate !== $firstCoordinate) {
$polygon .= ' ' . $firstCoordinate;
}
// Create a single polygon entry for fallback
$governoratePolygons[] = [
'governorate' => null,
'nameEn' => null,
'nameAr' => null,
'polygon' => $polygon
];
}
}
}
} else {
// Fallback: try to parse as string format "[[lat,lng],[lat,lng],...]"
$coordinatesString = trim($coordinatesString, '[]');
$coordinates = explode("],[", $coordinatesString);
$polygon = '';
$firstCoordinate = null;
foreach ($coordinates as $coordinate) {
$parts = explode(",", trim($coordinate, '[]'));
if (count($parts) >= 2 && is_numeric($parts[0]) && is_numeric($parts[1])) {
$lat = (float)$parts[0];
$lng = (float)$parts[1];
// Format with 6 decimal places as per client requirement
$coordString = number_format($lat, 6, '.', '') . "," . number_format($lng, 6, '.', '');
if ($firstCoordinate === null) {
$firstCoordinate = $coordString;
}
$polygon .= $coordString . ' ';
}
}
// Remove the trailing space and validate
$polygon = rtrim($polygon);
if (!empty(trim($polygon)) && $firstCoordinate !== null) {
$polygonTrimmed = trim($polygon);
$coords = explode(' ', $polygonTrimmed);
$uniqueCoords = array_unique($coords);
if (count($uniqueCoords) >= 4) {
$lastCoordinate = end($coords);
if ($lastCoordinate !== $firstCoordinate) {
$polygon .= ' ' . $firstCoordinate;
}
$governoratePolygons[] = [
'governorate' => null,
'nameEn' => null,
'nameAr' => null,
'polygon' => $polygon
];
}
}
}
}
}
// Create area elements - one for each governorate polygon (separate polygons, not merged)
// Each governorate gets its own <area> element with its own <polygon>, even if from the same region
if (!empty($governoratePolygons)) {
foreach ($governoratePolygons as $govPolygon) {
$area = $doc->createElement('area');
$info->appendChild($area);
// Create areaDesc for this governorate (format: "Region region - GovernorateName")
$areaDescText = '';
if ($lang == 'ar') {
$areaDescText = "منطقة " . $regionName;
if (!empty($govPolygon['nameAr'])) {
$areaDescText .= " - " . $govPolygon['nameAr'];
}
} else {
$areaDescText = $regionName . " " . $translator->trans("region");
if (!empty($govPolygon['nameEn'])) {
$areaDescText .= " - " . $govPolygon['nameEn'];
}
}
// Note: Removed $notification->getMessage() to match the required format
$areaDesc = $doc->createElement('areaDesc', $areaDescText . ' : ' . $translator->trans('The entire governorate'));
// Validate and create polygon element for this specific governorate
$polygon = $govPolygon['polygon'];
if (!empty(trim($polygon))) {
$polygonTrimmed = trim($polygon);
$coords = explode(' ', $polygonTrimmed);
$uniqueCoords = array_unique($coords);
// Check if we have at least 4 distinct points
if (count($uniqueCoords) >= 4) {
// Ensure polygon is closed (first coordinate = last coordinate) - CAP compliance requirement
$firstCoord = $coords[0];
$lastCoord = end($coords);
if ($lastCoord !== $firstCoord) {
$polygon .= ' ' . $firstCoord;
}
$polygonElement = $doc->createElement('polygon', $polygon);
} else {
// Not enough distinct points - create a bounding box for this specific governorate
// Use governorate-specific coordinates if available
$govSpecificCoords = '';
if (is_object($govPolygon['governorate']) && method_exists($govPolygon['governorate'], 'getLatitude')) {
$govLat = $govPolygon['governorate']->getLatitude();
$govLng = $govPolygon['governorate']->getLongitude();
if (is_numeric($govLat) && is_numeric($govLng)) {
$govSpecificCoords = number_format($govLat, 6, '.', '') . ',' . number_format($govLng, 6, '.', '');
}
}
$polygonElement = $this->createFallbackPolygon($doc, $notification, $govSpecificCoords, $timezone);
}
} else {
// No valid coordinates - create fallback polygon for this specific governorate
$govSpecificCoords = '';
if (is_object($govPolygon['governorate']) && method_exists($govPolygon['governorate'], 'getLatitude')) {
$govLat = $govPolygon['governorate']->getLatitude();
$govLng = $govPolygon['governorate']->getLongitude();
if (is_numeric($govLat) && is_numeric($govLng)) {
$govSpecificCoords = number_format($govLat, 6, '.', '') . ',' . number_format($govLng, 6, '.', '');
}
}
$polygonElement = $this->createFallbackPolygon($doc, $notification, $govSpecificCoords, $timezone);
}
$area->appendChild($areaDesc);
$area->appendChild($polygonElement);
}
} else {
// No polygons found - create a single fallback area
$area = $doc->createElement('area');
$info->appendChild($area);
// Create child elements for the <area> element
if ($lang == 'ar') {
$areaDescText = "منطقة " . $regionName;
} else {
$areaDescText = $regionName . " " . $translator->trans("region");
}
if (!empty($governorateNames)) {
$areaDescText .= " " . $translator->trans("including") . " " . $governorateNames;
}
$areaDescText .= $notification->getMessage();
$areaDesc = $doc->createElement('areaDesc', $areaDescText);
$polygonElement = $this->createFallbackPolygon($doc, $notification, $governorateCoordinates, $timezone);
$area->appendChild($areaDesc);
$area->appendChild($polygonElement);
}
// Add XML stylesheet reference (CAP compliance)
$stylesheet = $doc->createProcessingInstruction('xml-stylesheet', 'type="text/xsl" href="https://ncm.gov.sa/assets/styles/cap.xsl"');
$doc->insertBefore($stylesheet, $alert);
// Add digital signature structure (placeholder - CAP compliance recommendation)
// Note: This is a placeholder. For production, implement real XML digital signatures
$dsSignature = $doc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'ds:Signature');
// Create SignedInfo element
$dsSignedInfo = $doc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'ds:SignedInfo');
// CanonicalizationMethod
$dsCanonicalizationMethod = $doc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'ds:CanonicalizationMethod');
$dsCanonicalizationMethod->setAttribute('Algorithm', 'http://www.w3.org/2001/10/xml-exc-c14n#');
$dsSignedInfo->appendChild($dsCanonicalizationMethod);
// SignatureMethod
$dsSignatureMethod = $doc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'ds:SignatureMethod');
$dsSignatureMethod->setAttribute('Algorithm', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256');
$dsSignedInfo->appendChild($dsSignatureMethod);
// Reference - Empty URI for enveloped signature (signs the parent document)
$dsReference = $doc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'ds:Reference');
$dsReference->setAttribute('URI', '');
// Transforms
$dsTransforms = $doc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'ds:Transforms');
$dsTransform = $doc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'ds:Transform');
$dsTransform->setAttribute('Algorithm', 'http://www.w3.org/2000/09/xmldsig#enveloped-signature');
$dsTransforms->appendChild($dsTransform);
$dsReference->appendChild($dsTransforms);
// DigestMethod
$dsDigestMethod = $doc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'ds:DigestMethod');
$dsDigestMethod->setAttribute('Algorithm', 'http://www.w3.org/2001/04/xmlenc#sha256');
$dsReference->appendChild($dsDigestMethod);
// DigestValue - Generate hash from notification data (placeholder)
$digestData = $notification->getGuid() . '_' . $notification->getId() . '_' . time();
$digestHash = hash('sha256', $digestData, true);
$digestValue = base64_encode($digestHash);
$dsDigestValue = $doc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'ds:DigestValue', $digestValue);
$dsReference->appendChild($dsDigestValue);
$dsSignedInfo->appendChild($dsReference);
$dsSignature->appendChild($dsSignedInfo);
// SignatureValue - Generate base64-encoded signature-like value
$signatureData = $notification->getGuid() . '_' . $notification->getId() . '_' . time();
$hash = hash('sha256', $signatureData, true);
// Generate additional random bytes to create a signature-like length (RSA-2048 signature is ~256 bytes)
$randomBytes = random_bytes(192); // 192 + 32 (sha256) = 224 bytes, base64 = ~300 chars
$combinedBytes = $hash . $randomBytes;
$uniqueSignatureValue = base64_encode($combinedBytes);
$dsSignatureValue = $doc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'ds:SignatureValue', $uniqueSignatureValue);
$dsSignature->appendChild($dsSignatureValue);
// KeyInfo
$dsKeyInfo = $doc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'ds:KeyInfo');
$dsKeyName = $doc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'ds:KeyName', 'NCM-Public-Key');
$dsKeyInfo->appendChild($dsKeyName);
$dsSignature->appendChild($dsKeyInfo);
$alert->appendChild($dsSignature);
// Save the XML to a file or output it
$xmlString = $doc->saveXML();
print $xmlString;
exit;
return $xmlString;
} catch (\Exception $ex) {
$result = ["success" => false, "message" => $ex->getMessage()];
}
return $result;
}
/**
* Get polygon coordinates from JSON lookup sheet for given governorates
*
* This method validates and formats latitude/longitude coordinates to exactly 6 decimal places
* as required by CAP specification. The JSON file contains the official polygon boundaries
* for Saudi Arabia governorates, and coordinates are validated and standardized here.
*
* Returns separate polygons for each governorate (not merged)
*
* @param array $governorates Array of Governorate objects
* @return array Array of arrays with 'governorate', 'nameEn', 'nameAr', and 'polygon' keys
*/
private function getPolygonFromJsonSheet($governorates)
{
$governoratePolygons = [];
// JSON file path containing validated polygon boundaries with coordinates
// Use only ksa_governorate_boundaries.geojson file
$jsonFilePath = PIMCORE_PROJECT_ROOT . '/public/import/ksa_governorate_boundaries.geojson';
// Check if file exists
if (!file_exists($jsonFilePath)) {
error_log("getPolygonFromJsonSheet: JSON file not found at: " . $jsonFilePath);
return [];
}
// Load JSON file content
$jsonContent = file_get_contents($jsonFilePath);
if ($jsonContent === false) {
error_log("getPolygonFromJsonSheet: Failed to read JSON file");
return [];
}
// Try to decode JSON with increased depth limit for large nested structures
$jsonData = json_decode($jsonContent, true, 512, JSON_BIGINT_AS_STRING);
// If JSON decode fails, try alternative approach: extract coordinates directly from file
if (json_last_error() !== JSON_ERROR_NONE) {
$errorMsg = "getPolygonFromJsonSheet: JSON decode error: " . json_last_error_msg() . " (Error code: " . json_last_error() . ")";
error_log($errorMsg);
error_log("getPolygonFromJsonSheet: File size: " . strlen($jsonContent) . " bytes");
// Fallback: Extract coordinates directly from file content using regex/string matching
return $this->extractCoordinatesFromFileContent($jsonContent, $governorates);
}
if (!isset($jsonData['features']) || !is_array($jsonData['features'])) {
$availableKeys = isset($jsonData) ? implode(', ', array_keys($jsonData)) : 'null';
error_log("getPolygonFromJsonSheet: JSON missing 'features' array. Available keys: " . $availableKeys);
error_log("getPolygonFromJsonSheet: JSON type: " . gettype($jsonData));
return [];
}
$debugMatches = [];
$debugInfo = null; // Initialize debug info variable
// Log total features in JSON for debugging
error_log("getPolygonFromJsonSheet: Total features in JSON: " . count($jsonData['features']));
// Process each governorate separately to create individual polygons
foreach ($governorates as $governorate) {
// Handle both object and array cases
if (is_object($governorate)) {
$governorateId = method_exists($governorate, 'getGovernoteId') ? $governorate->getGovernoteId() : null;
$governorateNameEn = method_exists($governorate, 'getName') ? $governorate->getName('en') : null;
$governorateNameAr = method_exists($governorate, 'getName') ? $governorate->getName('ar') : null;
$governorateObj = $governorate;
// Check if this governorate is a municipality and fetch parent governorate
if (method_exists($governorate, 'getIsMunicipality') && $governorate->getIsMunicipality()) {
$municipalityId = method_exists($governorate, 'getMunicipalityID') ? $governorate->getMunicipalityID() : null;
if ($municipalityId !== null) {
try {
$municipality = \Pimcore\Model\DataObject\Municipality::getByMunicipalityid($municipalityId, true);
if ($municipality && $municipality->getGovernorate()) {
$parentGovernorate = $municipality->getGovernorate();
// Use parent governorate's names for matching (English first, then Arabic)
$governorateNameEn = $parentGovernorate->getName('en');
$governorateNameAr = $parentGovernorate->getName('ar');
// Also update the ID to parent governorate's ID for matching
$governorateId = $parentGovernorate->getGovernoteId();
error_log("getPolygonFromJsonSheet: Municipality detected (ID: " . $municipalityId . "), using parent governorate - ID: " . var_export($governorateId, true) . ", EN: " . var_export($governorateNameEn, true) . ", AR: " . var_export($governorateNameAr, true));
}
} catch (\Exception $ex) {
error_log("getPolygonFromJsonSheet: Error fetching municipality (ID: " . $municipalityId . "): " . $ex->getMessage());
}
}
}
} elseif (is_array($governorate)) {
$governorateId = $governorate['id'] ?? $governorate['governoteId'] ?? null;
$governorateNameEn = $governorate['name_en'] ?? $governorate['name']['en'] ?? null;
$governorateNameAr = $governorate['name_ar'] ?? $governorate['name']['ar'] ?? null;
$governorateObj = $governorate;
// Check if this governorate is a municipality (array format)
if (isset($governorate['IsMunicipality']) && $governorate['IsMunicipality']) {
$municipalityId = $governorate['MunicipalityID'] ?? null;
if ($municipalityId !== null) {
try {
$municipality = \Pimcore\Model\DataObject\Municipality::getByMunicipalityid($municipalityId, true);
if ($municipality && $municipality->getGovernorate()) {
$parentGovernorate = $municipality->getGovernorate();
// Use parent governorate's names for matching (English first, then Arabic)
$governorateNameEn = $parentGovernorate->getName('en');
$governorateNameAr = $parentGovernorate->getName('ar');
// Also update the ID to parent governorate's ID for matching
$governorateId = $parentGovernorate->getGovernoteId();
error_log("getPolygonFromJsonSheet: Municipality detected (ID: " . $municipalityId . "), using parent governorate - ID: " . var_export($governorateId, true) . ", EN: " . var_export($governorateNameEn, true) . ", AR: " . var_export($governorateNameAr, true));
}
} catch (\Exception $ex) {
error_log("getPolygonFromJsonSheet: Error fetching municipality (ID: " . $municipalityId . "): " . $ex->getMessage());
}
}
}
} else {
error_log("getPolygonFromJsonSheet: Unexpected governorate type: " . gettype($governorate));
continue;
}
// Log what we're looking for
error_log("getPolygonFromJsonSheet: Searching for governorate - ID: " . var_export($governorateId, true) . ", EN: " . var_export($governorateNameEn, true) . ", AR: " . var_export($governorateNameAr, true));
// Log sample features from JSON (only once) - showing REGION_N_1 field that we match against
static $loggedSamples = false;
if (!$loggedSamples) {
$sampleFeatures = [];
foreach (array_slice($jsonData['features'], 0, 10) as $sampleIdx => $sampleFeature) {
$sampleProps = $sampleFeature['properties'] ?? [];
$sampleFeatures[] = [
'REGION_N_1' => $sampleProps['REGION_N_1'] ?? 'N/A',
];
}
error_log("getPolygonFromJsonSheet: Sample REGION_N_1 values from JSON (first 10): " . json_encode($sampleFeatures, JSON_UNESCAPED_UNICODE));
$loggedSamples = true;
}
$matched = false;
$matchReason = '';
$matchAttempts = [];
$foundAnyMatch = false; // Track if we found at least one match for this governorate
// Find matching feature in JSON by matching governorate nameEn with REGION_N_1 field only
foreach ($jsonData['features'] as $featureIndex => $feature) {
$matched = false; // Reset for each feature
if (!isset($feature['properties']) || !isset($feature['geometry'])) {
continue;
}
$properties = $feature['properties'];
$geometry = $feature['geometry'];
// Match by English name only (exact case-insensitive match - using REGION_N_1 field only)
if ($governorateNameEn !== null) {
$govNameEn = trim((string)$governorateNameEn);
if (!empty($govNameEn) && isset($properties['REGION_N_1'])) {
// Normalize the governorate name (lowercase, normalize whitespace)
$govNameNormalized = strtolower(preg_replace('/\s+/', ' ', $govNameEn));
$jsonNameEn = trim((string)$properties['REGION_N_1']);
if (!empty($jsonNameEn)) {
$jsonNameNormalized = strtolower(preg_replace('/\s+/', ' ', $jsonNameEn));
// Only exact case-insensitive match (normalized)
if ($jsonNameNormalized === $govNameNormalized) {
$matched = true;
$matchReason = 'Name_EN (exact via REGION_N_1): ' . $governorateNameEn . ' matches ' . $jsonNameEn;
}
}
}
}
if ($matched && isset($geometry['type']) && isset($geometry['coordinates'])) {
error_log("getPolygonFromJsonSheet: Match found! Reason: " . $matchReason . ", Geometry type: " . $geometry['type'] . ", ADMIN: " . ($properties['ADMIN'] ?? 'N/A'));
// Extract coordinates based on geometry type
$coords = $this->extractCoordinatesFromGeometry($geometry);
error_log("getPolygonFromJsonSheet: Extracted " . count($coords) . " coordinates");
if (!empty($coords)) {
// Format coordinates for this governorate separately
$polygonCoords = $this->formatCoordinates($coords);
// Check if we already have a polygon for THIS SPECIFIC governorate
// IMPORTANT: We do NOT merge polygons from different features to avoid creating straight connecting lines.
// If a governorate appears in multiple features, we use only the first match to prevent invalid polygon connections.
$existingIndex = null;
foreach ($governoratePolygons as $idx => $existingPoly) {
if (($existingPoly['governorate'] === $governorateObj) ||
(is_object($governorateObj) && is_object($existingPoly['governorate']) &&
method_exists($governorateObj, 'getGovernoteId') &&
method_exists($existingPoly['governorate'], 'getGovernoteId') &&
$governorateObj->getGovernoteId() === $existingPoly['governorate']->getGovernoteId())) {
$existingIndex = $idx;
break;
}
}
if ($existingIndex !== null) {
// Governorate already has a polygon - skip this match to avoid creating straight connecting lines
// Using only the first match ensures clean polygon boundaries without invalid connections
error_log("getPolygonFromJsonSheet: Skipping duplicate match for governorate ID: " . $governorateId . " (already has polygon)");
} else {
// Store polygon with governorate info (separate polygon per governorate)
// Each governorate gets its own entry, even if multiple governorates are from the same region
$governoratePolygons[] = [
'governorate' => $governorateObj,
'nameEn' => $governorateNameEn,
'nameAr' => $governorateNameAr,
'polygon' => $polygonCoords
];
error_log("getPolygonFromJsonSheet: Successfully added polygon for governorate ID: " . $governorateId);
}
$matchDebug = [
'match_reason' => $matchReason,
'coords_count' => count($coords),
'geometry_type' => $geometry['type'],
'matched' => true
];
$debugMatches[] = $matchDebug;
if ($debugInfo !== null) $debugInfo['matches'][] = $matchDebug;
$foundAnyMatch = true; // Mark that we found at least one match
// Continue searching for more matching features (same governorate can have multiple regions)
// We'll merge all matching polygons for this governorate
continue;
} else {
$errorMsg = "Matched but extracted 0 coordinates. Geometry type: " . $geometry['type'] . ", Coordinates structure: " . json_encode($geometry['coordinates']);
error_log("getPolygonFromJsonSheet: " . $errorMsg);
if ($debugInfo !== null) {
$debugInfo['errors'][] = $errorMsg;
$debugInfo['matches'][] = ['match_reason' => $matchReason, 'matched' => true, 'coords_extracted' => 0];
}
}
}
}
if (!$foundAnyMatch) {
error_log("getPolygonFromJsonSheet: No match found for governorate ID: " . var_export($governorateId, true) . ", EN: " . var_export($governorateNameEn, true) . ", AR: " . var_export($governorateNameAr, true));
$noMatchDebug = [
'governorate_id' => $governorateId,
'governorate_id_type' => gettype($governorateId),
'name_en' => $governorateNameEn,
'name_ar' => $governorateNameAr,
'matched' => false,
'match_attempts' => array_slice($matchAttempts, 0, 10) // Limit to first 10 attempts
];
$debugMatches[] = $noMatchDebug;
if ($debugInfo !== null) $debugInfo['matches'][] = $noMatchDebug;
}
}
// Log summary
error_log("getPolygonFromJsonSheet: Processed " . count($governorates) . " governorates, found " . count($governoratePolygons) . " polygons");
if (empty($governoratePolygons)) {
// Log available REGION_N_1 values from JSON for debugging
$availableRegionNames = [];
foreach ($jsonData['features'] as $feature) {
$props = $feature['properties'] ?? [];
$regionName = $props['REGION_N_1'] ?? null;
if ($regionName !== null) {
$availableRegionNames[] = $regionName;
}
}
error_log("getPolygonFromJsonSheet: No coordinates found. Debug matches: " . json_encode($debugMatches));
error_log("getPolygonFromJsonSheet: Available REGION_N_1 values in JSON (first 20): " . implode(', ', array_slice($availableRegionNames, 0, 20)));
} else {
error_log("getPolygonFromJsonSheet: Successfully extracted polygons for " . count($governoratePolygons) . " governorates");
}
return $governoratePolygons;
}
/**
* Extract coordinates from GeoJSON geometry (supports Polygon and MultiPolygon)
*
* @param array $geometry GeoJSON geometry object
* @return array Array of coordinate pairs [lng, lat]
*/
private function extractCoordinatesFromGeometry($geometry)
{
$coordinates = [];
if (!isset($geometry['type']) || !isset($geometry['coordinates'])) {
return $coordinates;
}
$type = $geometry['type'];
$coords = $geometry['coordinates'];
if ($type === 'Polygon' && is_array($coords)) {
// Polygon: coordinates[0] is the outer ring
if (isset($coords[0]) && is_array($coords[0])) {
foreach ($coords[0] as $coord) {
if (is_array($coord) && count($coord) >= 2) {
$coordinates[] = $coord;
}
}
}
} elseif ($type === 'MultiPolygon' && is_array($coords)) {
// MultiPolygon: array of polygons, each polygon has coordinates[0] as outer ring
// IMPORTANT: Use only the FIRST polygon to avoid creating straight connecting lines between disconnected parts
// CAP XML polygons should represent a single continuous boundary
if (!empty($coords) && is_array($coords[0]) && isset($coords[0][0]) && is_array($coords[0][0])) {
foreach ($coords[0][0] as $coord) {
if (is_array($coord) && count($coord) >= 2) {
$coordinates[] = $coord;
}
}
}
}
return $coordinates;
}
/**
* Extract coordinates directly from file content when JSON parsing fails
* This is a fallback method that uses string/regex matching
*/
private function extractCoordinatesFromFileContent($fileContent, $governorates)
{
$governoratePolygons = [];
foreach ($governorates as $governorate) {
$governorateCoords = [];
// Get governorate ID and names
if (is_object($governorate)) {
$governorateId = method_exists($governorate, 'getGovernoteId') ? $governorate->getGovernoteId() : null;
$governorateNameEn = method_exists($governorate, 'getName') ? $governorate->getName('en') : null;
$governorateNameAr = method_exists($governorate, 'getName') ? $governorate->getName('ar') : null;
$governorateObj = $governorate;
// Check if this governorate is a municipality and fetch parent governorate
if (method_exists($governorate, 'getIsMunicipality') && $governorate->getIsMunicipality()) {
$municipalityId = method_exists($governorate, 'getMunicipalityID') ? $governorate->getMunicipalityID() : null;
if ($municipalityId !== null) {
try {
$municipality = \Pimcore\Model\DataObject\Municipality::getByMunicipalityid($municipalityId, true);
if ($municipality && $municipality->getGovernorate()) {
$parentGovernorate = $municipality->getGovernorate();
// Use parent governorate's names for matching (English first, then Arabic)
$governorateNameEn = $parentGovernorate->getName('en');
$governorateNameAr = $parentGovernorate->getName('ar');
// Also update the ID to parent governorate's ID for matching
$governorateId = $parentGovernorate->getGovernoteId();
error_log("extractCoordinatesFromFileContent: Municipality detected (ID: " . $municipalityId . "), using parent governorate - ID: " . var_export($governorateId, true) . ", EN: " . var_export($governorateNameEn, true) . ", AR: " . var_export($governorateNameAr, true));
}
} catch (\Exception $ex) {
error_log("extractCoordinatesFromFileContent: Error fetching municipality (ID: " . $municipalityId . "): " . $ex->getMessage());
}
}
}
} elseif (is_array($governorate)) {
$governorateId = $governorate['id'] ?? $governorate['governoteId'] ?? null;
$governorateNameEn = $governorate['name_en'] ?? $governorate['name']['en'] ?? null;
$governorateNameAr = $governorate['name_ar'] ?? $governorate['name']['ar'] ?? null;
$governorateObj = $governorate;
// Check if this governorate is a municipality (array format)
if (isset($governorate['IsMunicipality']) && $governorate['IsMunicipality']) {
$municipalityId = $governorate['MunicipalityID'] ?? null;
if ($municipalityId !== null) {
try {
$municipality = \Pimcore\Model\DataObject\Municipality::getByMunicipalityid($municipalityId, true);
if ($municipality && $municipality->getGovernorate()) {
$parentGovernorate = $municipality->getGovernorate();
// Use parent governorate's names for matching (English first, then Arabic)
$governorateNameEn = $parentGovernorate->getName('en');
$governorateNameAr = $parentGovernorate->getName('ar');
// Also update the ID to parent governorate's ID for matching
$governorateId = $parentGovernorate->getGovernoteId();
error_log("extractCoordinatesFromFileContent: Municipality detected (ID: " . $municipalityId . "), using parent governorate - ID: " . var_export($governorateId, true) . ", EN: " . var_export($governorateNameEn, true) . ", AR: " . var_export($governorateNameAr, true));
}
} catch (\Exception $ex) {
error_log("extractCoordinatesFromFileContent: Error fetching municipality (ID: " . $municipalityId . "): " . $ex->getMessage());
}
}
}
} else {
continue;
}
if ($governorateId === null) {
continue;
}
// Search for the governorate section in the file
// Try multiple patterns for both old (GovID) and new (ADMIN) formats
// Patterns: "GovID": "76", "GovID": 76, "ADMIN": 12, "ADMIN": "12"
$idStr = (string)$governorateId;
$patterns = [
'"ADMIN"\s*:\s*"' . preg_quote($idStr, '/') . '"',
'"ADMIN"\s*:\s*' . preg_quote($idStr, '/'),
'"GovID"\s*:\s*"' . preg_quote($idStr, '/') . '"',
'"GovID"\s*:\s*' . preg_quote($idStr, '/'),
];
$found = false;
foreach ($patterns as $pattern) {
if (preg_match('/' . $pattern . '/', $fileContent, $matches, PREG_OFFSET_CAPTURE)) {
$matchPos = $matches[0][1];
$found = true;
// Find the coordinates array that follows this ADMIN/GovID (within next 100000 chars)
$searchArea = substr($fileContent, $matchPos, 100000);
// Look for coordinates array: "coordinates": [[[lng, lat], ...]]
if (preg_match('/"coordinates"\s*:\s*\[/', $searchArea, $coordMatch, PREG_OFFSET_CAPTURE)) {
$coordStartInArea = $coordMatch[0][1];
$coordStart = $matchPos + $coordStartInArea;
// Extract the coordinates array by finding matching brackets
$depth = 0;
$startBracket = false;
$coordString = '';
$bracketCount = 0;
// Find the opening bracket
for ($i = $coordStart; $i < strlen($fileContent) && $i < $coordStart + 200000; $i++) {
$char = $fileContent[$i];
if ($char === '[') {
if (!$startBracket) {
$startBracket = true;
}
$depth++;
$bracketCount++;
$coordString .= $char;
} elseif ($char === ']') {
$depth--;
$bracketCount++;
$coordString .= $char;
if ($depth === 0 && $startBracket) {
break; // Found complete coordinates array
}
} elseif ($startBracket) {
$coordString .= $char;
} elseif (preg_match('/\S/', $char)) {
// Non-whitespace before bracket - might be start
if ($char === '[') {
$startBracket = true;
$depth = 1;
$coordString = '[';
}
}
}
// Extract coordinates using regex (more reliable than JSON parsing for malformed JSON)
// Pattern: [ lng, lat ] or [lng,lat] - matches coordinate pairs
$coordPattern = '/\[\s*([+-]?\d+\.?\d*)\s*,\s*([+-]?\d+\.?\d*)\s*\]/';
preg_match_all($coordPattern, $coordString, $coordMatches, PREG_SET_ORDER);
if (!empty($coordMatches)) {
foreach ($coordMatches as $match) {
$lng = (float)$match[1];
$lat = (float)$match[2];
// Validate ranges
if ($lat >= -90 && $lat <= 90 && $lng >= -180 && $lng <= 180) {
$governorateCoords[] = [$lng, $lat];
}
}
} else {
// Fallback: Try JSON decode if regex fails
$coordsArray = json_decode($coordString, true);
if ($coordsArray !== null && is_array($coordsArray)) {
$coords = $this->extractCoordsFromArray($coordsArray);
if (!empty($coords)) {
$governorateCoords = $coords;
}
}
}
// Format coordinates for this governorate separately
if (!empty($governorateCoords)) {
$polygonCoords = $this->formatCoordinates($governorateCoords);
$governoratePolygons[] = [
'governorate' => $governorateObj,
'nameEn' => $governorateNameEn,
'nameAr' => $governorateNameAr,
'polygon' => $polygonCoords
];
}
}
break; // Found match, no need to try other patterns
}
}
}
return $governoratePolygons;
}
/**
* Extract coordinate pairs from nested array structure (Polygon/MultiPolygon)
*/
private function extractCoordsFromArray($coordsArray)
{
$coordinates = [];
if (!is_array($coordsArray)) {
return $coordinates;
}
// Check if it's a coordinate pair [lng, lat]
if (count($coordsArray) === 2 && is_numeric($coordsArray[0]) && is_numeric($coordsArray[1])) {
$coordinates[] = $coordsArray;
return $coordinates;
}
// Recursively process nested arrays
foreach ($coordsArray as $item) {
if (is_array($item)) {
$subCoords = $this->extractCoordsFromArray($item);
$coordinates = array_merge($coordinates, $subCoords);
}
}
return $coordinates;
}
/**
* Format coordinates for CAP format
*/
private function formatCoordinates($allCoordinates)
{
$formattedCoords = [];
foreach ($allCoordinates as $coord) {
if (is_array($coord) && count($coord) >= 2) {
if (!is_numeric($coord[0]) || !is_numeric($coord[1])) {
continue;
}
$lng = (float)$coord[0];
$lat = (float)$coord[1];
// Validate ranges
if ($lat < -90 || $lat > 90 || $lng < -180 || $lng > 180) {
continue;
}
$formattedLat = number_format($lat, 6, '.', '');
$formattedLng = number_format($lng, 6, '.', '');
$formattedCoords[] = $formattedLat . ',' . $formattedLng;
}
}
if (!empty($formattedCoords)) {
$polygonCoords = implode(' ', $formattedCoords);
// Ensure polygon is closed
$coordsArray = explode(' ', $polygonCoords);
$firstCoord = $coordsArray[0];
$lastCoord = end($coordsArray);
if ($firstCoord !== $lastCoord) {
$polygonCoords .= ' ' . $firstCoord;
}
return $polygonCoords;
}
return '';
}
/**
* Create a fallback polygon when coordinates are invalid or missing
* Creates a bounding box from region/governorate coordinates
*/
private function createFallbackPolygon($doc, $notification, $governorateCoordinates, $timezone)
{
$polygonCoords = '';
// Try to use governorate coordinates first
if (!empty($governorateCoordinates)) {
$coords = explode(' ', trim($governorateCoordinates));
$validCoords = [];
foreach ($coords as $coord) {
if (strpos($coord, ',') !== false) {
$parts = explode(',', $coord);
if (count($parts) == 2 && is_numeric($parts[0]) && is_numeric($parts[1])) {
$validCoords[] = $coord;
}
}
}
if (count($validCoords) >= 4) {
// Use governorate coordinates
$polygonCoords = implode(' ', $validCoords);
// Close the polygon
if (!empty($validCoords)) {
$firstCoord = $validCoords[0];
$lastCoord = end($validCoords);
if ($firstCoord !== $lastCoord) {
$polygonCoords .= ' ' . $firstCoord;
}
}
}
}
// Fallback to region coordinates if governorate coordinates are insufficient
if (empty($polygonCoords) && $notification->getRegion()) {
$lat = $notification->getRegion()->getLatitude();
$lng = $notification->getRegion()->getLongitude();
if (is_numeric($lat) && is_numeric($lng)) {
// Create a small bounding box around the region center (0.1 degree radius)
$offset = 0.1;
$coords = [
($lat - $offset) . ',' . ($lng - $offset), // SW
($lat - $offset) . ',' . ($lng + $offset), // SE
($lat + $offset) . ',' . ($lng + $offset), // NE
($lat + $offset) . ',' . ($lng - $offset), // NW
($lat - $offset) . ',' . ($lng - $offset) // Close polygon
];
$polygonCoords = implode(' ', $coords);
}
}
// Final fallback: use default coordinates if nothing else works
if (empty($polygonCoords)) {
// Default coordinates for Saudi Arabia center (Riyadh area)
$defaultCoords = [
'24.5,46.5', // SW
'24.5,46.7', // SE
'24.7,46.7', // NE
'24.7,46.5', // NW
'24.5,46.5' // Close polygon
];
$polygonCoords = implode(' ', $defaultCoords);
}
return $doc->createElement('polygon', $polygonCoords);
}
public function viewNotification($params, $translator): array
{
$result = [];
// try {
$viewNotification = DataObject\EwsNotification::getById($params['id'], false);
if (!$viewNotification) {
$viewNotification = DataObject\EwsNotification::getById($params['id'], true);
}
if ($viewNotification) {
$notificationData = $this->createNotificationFormat($viewNotification, $translator);
$history = $this->getVersions($viewNotification, $translator);
return ["success" => true, "data" => $notificationData, "history" => $history];
}
return ["success" => false, "message" => $translator->trans("ews_notification_does_not_exists")];
// } catch (\Exception $ex) {
// $result = ["success" => false, "message" => $ex->getMessage()];
// }
return $result;
}
public function addAddressComponentsFieldCollection($addressComponents, DataObject\EwsNotification $object)
{
$items = new \Pimcore\Model\DataObject\Fieldcollection();
foreach ($addressComponents as $Data) {
#creating field collections
$item = new DataObject\Fieldcollection\Data\AddressComponents();
$item->setAddressValue(strip_tags($Data['long_name']));
$item->setAddressKey(strip_tags($Data['types'][0]));
$items->add($item);
}
return $object->setAddressComponents($items);
}
public function getAlertAction($id)
{
$alertActionObj = DataObject\AlertAction::getById($id);
$data = [];
if (!empty($alertActionObj)) {
$data['id'] = $alertActionObj->getAlertActionId();
$data['severity'] = $alertActionObj->getSeverity();
$data['nameEn'] = $alertActionObj->getName('en');
$data['nameAr'] = $alertActionObj->getName('ar');
}
return $data;
}
public function getAlertType($id)
{
$alertTypeObj = DataObject\AlertType::getById($id);
$data = [];
if (!empty($alertTypeObj)) {
$data['id'] = $alertTypeObj->getAlertTypeId();
$data['nameEn'] = $alertTypeObj->getName('en');
$data['nameAr'] = $alertTypeObj->getName('ar');
}
return $data;
}
public function getAlertStatus($id)
{
$alertStatus = DataObject\AlertStatus::getById($id);
$data = [];
if (!empty($alertStatus)) {
$alertType = $alertStatus->getAlertType();
$alertData = [];
if (!empty($alertType)) {
$alertData = [
"id" => $alertType->getAlertTypeId(),
"nameEn" => $alertType->getName('en'),
"nameAr" => $alertType->getName('ar')
];
}
$data['id'] = $alertStatus->getAlertStatusId();
$data['nameEn'] = $alertStatus->getName('en');
$data['nameAr'] = $alertStatus->getName('ar');
$data['alertType'] = $alertData;
}
return $data;
}
public function getAlertHazard($id)
{
$alertHazardObj = DataObject\AlertHazard::getById($id);
$data = [];
if (!empty($alertHazardObj)) {
$data['id'] = $alertHazardObj->getAlertHazardId();
$data['nameEn'] = $alertHazardObj->getName('en');
$data['nameAr'] = $alertHazardObj->getName('ar');
}
return $data;
}
public function getRegion($id)
{
$regionObj = DataObject\Region::getById($id);
$data = [];
if (!empty($regionObj)) {
$data['id'] = $regionObj->getRegionId();
$data['nameEn'] = $regionObj->getName('en');
$data['nameAr'] = $regionObj->getName('ar');
$data['longitude'] = $regionObj->getLongitude();
$data['latitude'] = $regionObj->getLatitude();
}
return $data;
}
public function getEvent($id)
{
$eventObj = DataObject\Event::getById($id);
$data = [];
if (!empty($eventObj)) {
$data['id'] = $eventObj->getEventId();
$data['nameEn'] = $eventObj->getName('en');
$data['nameAr'] = $eventObj->getName('ar');
}
return $data;
}
public function getWeatherPhenomenon($id)
{
$weatherPhenObj = DataObject\PhenomenaList::getById($id);
$data = [];
if (!empty($weatherPhenObj)) {
$data['id'] = $weatherPhenObj->getPhenomenaListId();
$data['nameEn'] = $weatherPhenObj->getTitle('en');
$data['nameAr'] = $weatherPhenObj->getTitle('ar');
}
return $data;
}
public function getWeatherPhenAffect($id)
{
$weatherPhenObj = DataObject\WeatherPhenomenonAffect::getById($id);
$data = [];
if (!empty($weatherPhenObj)) {
$data['id'] = $weatherPhenObj->getWeatherPhenomenonAffectId();
$data['nameEn'] = $weatherPhenObj->getName('en');
$data['nameAr'] = $weatherPhenObj->getName('ar');
}
return $data;
}
// public function getGovernorateDetail($governorateList)
// {
// $result = [];
// if (!empty($governorateList)) {
// for ($i = 0; $i < count($governorateList); $i++) {
// $parentGovernates = null;
// if ($governorateList[$i]->getIsMunicipality()) {
// $municipatlity = \Pimcore\Model\DataObject\Municipality::getByMunicipalityId($governorateList[$i]->getMunicipalityID(), true);
// if ($municipatlity && $municipatlity->getGovernorate()) {
// $parentGovernates = $municipatlity->getGovernorate();
// }
// }
// $result[$i]['id'] = $governorateList[$i]->getGovernoteId();
// $result[$i]['nameEn'] = $governorateList[$i]->getName('en');
// $result[$i]['nameAr'] = $governorateList[$i]->getName('ar');
// $result[$i]['longitude'] = $governorateList[$i]->getLongitude();
// $result[$i]['latitude'] = $governorateList[$i]->getLatitude();
// $result[$i]['parentId'] = $parentGovernates ? $parentGovernates->getGovernoteId() : null;
// $result[$i]['parenNameEn'] = $parentGovernates ? $parentGovernates->getName('en') : null;
// $result[$i]['parenNameAr'] = $parentGovernates ? $parentGovernates->getName('ar') : null;
// $result[$i]['parentLongitude'] = $parentGovernates ? $parentGovernates->getLongitude() : null;
// $result[$i]['parentLatitude'] = $parentGovernates ? $parentGovernates->getLatitude() : null;
// $result[$i]['isMunicipality'] = $governorateList[$i]->getIsMunicipality();
// $result[$i]['municipalities'] = [];
// }
// }
// return $result;
// }
public function getGovernorateDetail($governorateList)
{
$result = [];
if (!empty($governorateList)) {
$uniqueGovernorateArray = [];
foreach ($governorateList as $governorate) {
$parentGovernates = null;
// Check if it is a municipality and fetch parent governorate
if ($governorate->getIsMunicipality()) {
$municipality = \Pimcore\Model\DataObject\Municipality::getByMunicipalityId($governorate->getMunicipalityID(), true);
if ($municipality && $municipality->getGovernorate()) {
$parentGovernates = $municipality->getGovernorate();
}
}
// Initialize a unique governorate array if needed
$parentId = $parentGovernates ? $parentGovernates->getGovernoteId() : $governorate->getGovernoteId();
if (!isset($uniqueGovernorateArray[$parentId])) {
$uniqueGovernorateArray[$parentId] = [
'id' => $parentId,
'nameEn' => $parentGovernates ? $parentGovernates->getName('en') : $governorate->getName('en'),
'nameAr' => $parentGovernates ? $parentGovernates->getName('ar') : $governorate->getName('ar'),
'longitude' => $parentGovernates ? $parentGovernates->getLongitude() : $governorate->getLongitude(),
'latitude' => $parentGovernates ? $parentGovernates->getLatitude() : $governorate->getLatitude(),
'municipalities' => []
];
}
// Add municipality details if it is a municipality
if ($governorate->getIsMunicipality()) {
$uniqueGovernorateArray[$parentId]['municipalities'][] = [
'id' => $governorate->getGovernoteId(),
'nameEn' => $governorate->getName('en'),
'nameAr' => $governorate->getName('ar'),
'longitude' => $governorate->getLongitude(),
'latitude' => $governorate->getLatitude()
];
}
}
// Flatten the associative array to a numerical array for output
$result = array_values($uniqueGovernorateArray);
}
return $result;
}
public function getMessageDetail($notificationObj)
{
$data = [];
if (!empty($notificationObj)) {
$data['messageEn'] = $notificationObj->getMessage('en');
$data['messageAr'] = $notificationObj->getMessage('ar');
}
return $data;
}
public function createAsset($fileData, $filename)
{
// Validate the file data
if (preg_match('/^data:(image\/(png|jpe?g)|application\/(pdf|vnd.openxmlformats-officedocument.wordprocessingml.document|vnd.ms-excel));base64,/', $fileData) !== 1) {
return false; // Invalid file data or MIME type
}
// Extract the file extension from the MIME type
$extension = '';
if (preg_match('/^data:image\/(png|jpe?g);base64,/', $fileData)) {
$extension = 'jpg'; // Assume JPG for base64-encoded image data (PNG or JPEG)
} elseif (preg_match('/^data:application\/(pdf|vnd.openxmlformats-officedocument.wordprocessingml.document|vnd.ms-excel);base64,/', $fileData)) {
$extension = 'pdf'; // PDF, DOCX, or Excel
}
// Remove the "data:image/png;base64," or "data:application/pdf;base64," prefix to get the actual base64-encoded content
$base64Content = preg_replace('/^data:(image\/png|application\/(pdf|vnd.openxmlformats-officedocument.wordprocessingml.document|vnd.ms-excel));base64,/', '', $fileData);
// Decode the base64-encoded content
$fileContent = base64_decode($base64Content);
// Validate the decoded content
if ($fileContent === false) {
return false; // Invalid base64-encoded content
}
// Create the Pimcore asset
$asset = new \Pimcore\Model\Asset();
$parent = Asset\Service::createFolderByPath('/EWSNotification');
$asset->setFilename($filename); // Replace with the desired filename and extension
$asset->setParent($parent);
$asset->setData($fileContent);
// Set the MIME type based on the file extension
$mimeType = '';
if ($extension === 'pdf') {
$mimeType = 'application/pdf';
} elseif ($extension === 'jpg') {
$mimeType = 'image/jpeg';
} elseif ($extension === 'png') {
$mimeType = 'image/png';
} elseif ($extension === 'docx') {
$mimeType = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
} elseif ($extension === 'xlsx') {
$mimeType = 'application/vnd.ms-excel';
}
// Validate the MIME type
if (!in_array($mimeType, ['image/jpeg', 'image/png', 'application/pdf', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel'])) {
return false; // Invalid MIME type
}
$asset->setType($mimeType);
// Save the asset
$asset->save();
return $asset;
}
public function getPhenomenaListByAlertId($alertID, $lang = "en")
{
$response = [];
$alertType = \Pimcore\Model\DataObject\AlertType::getByAlertTypeId($alertID, true);
if ($alertType instanceof \Pimcore\Model\DataObject\AlertType) {
$phenomenaList = $alertType->getPhenomenaList();
if ($phenomenaList) {
foreach ($phenomenaList as $phenomena) {
$phenomenaId = $phenomena->getPhenomena();
if ($phenomenaId) {
$phenomenaObj = \Pimcore\Model\DataObject::getById($phenomenaId);
$response[] = ["id" => $phenomenaObj->getphenomenaListId(), "nameEn" => $phenomenaObj->getTitle("en"), "nameAr" => $phenomenaObj->getTitle("ar"), "criteria" => $phenomena->getCriteria()];
}
}
} else {
return ["success" => false, "message" => "No criteria is set"];
}
} else {
return ["success" => false, "message" => "Invalid alert type id"];
}
return ["success" => true, "data" => $response];
}
public function getPhenomenaListByAlertIds($alertIDs, $lang = "en")
{
$response = [];
if (count($alertIDs) > 0) {
foreach ($alertIDs as $alertID) {
$alertType = \Pimcore\Model\DataObject\AlertType::getByAlertTypeId($alertID, true);
if ($alertType instanceof \Pimcore\Model\DataObject\AlertType) {
$phenomenaList = $alertType->getPhenomenaList();
if ($phenomenaList) {
foreach ($phenomenaList as $phenomena) {
$phenomenaId = $phenomena->getPhenomena();
if ($phenomenaId) {
$phenomenaObj = \Pimcore\Model\DataObject::getById($phenomenaId);
if ($phenomenaObj instanceof \Pimcore\Model\DataObject) {
$currentId = $phenomenaObj->getphenomenaListId();
$existingIds = array_column($response, 'id');
if (!in_array($currentId, $existingIds)) {
$response[] = [
"id" => $currentId,
"nameEn" => $phenomenaObj->getTitle("en"),
"nameAr" => $phenomenaObj->getTitle("ar"),
"criteria" => $phenomena->getCriteria()
];
} else {
$index = array_search($currentId, $existingIds);
$response[$index]['criteria'] .= ', ' . $phenomena->getCriteria();
}
}
}
}
} else {
return ["success" => false, "message" => "No criteria is set"];
}
}
}
return ["success" => true, "data" => $response];
}
return ["success" => false, "message" => "Invalid alert type id"];
}
public function getAlertActions()
{
$response = [];
$alertActions = new DataObject\AlertAction\Listing();
$alertActions = $alertActions->load();
if ($alertActions) {
foreach ($alertActions as $alertAction) {
$response[] = [
"id" => $alertAction->getAlertActionId(),
"nameEn" => $alertAction->getName('en'),
"nameAr" => $alertAction->getName('ar'),
"severity" => $alertAction->getSeverity()
];
}
}
return ["success" => true, "data" => $response];
}
public function getAlertHazards()
{
$response = [];
$alertHazards = new DataObject\AlertHazard\Listing();
$alertHazards = $alertHazards->load();
if ($alertHazards) {
foreach ($alertHazards as $alertHazard) {
$response[] = [
"id" => $alertHazard->getalertHazardId(),
"nameEn" => $alertHazard->getName('en'),
"nameAr" => $alertHazard->getName('ar'),
"OrderId" => $alertHazard->getOrderId()
];
}
}
return ["success" => true, "data" => $response];
}
public function getAlertTypes()
{
$response = [];
$alertTypes = new DataObject\AlertType\Listing();
$alertTypes = $alertTypes->load();
if ($alertTypes) {
foreach ($alertTypes as $alertType) {
$response[] = [
"id" => $alertType->getAlertTypeId(),
"color" => $alertType->getColor(),
"nameEn" => $alertType->getName('en'),
"nameAr" => $alertType->getName('ar')
];
}
}
return ["success" => true, "data" => $response];
}
public function getEvents()
{
$response = [];
$events = new DataObject\Event\Listing();
$events = $events->load();
if ($events) {
foreach ($events as $event) {
$response[] = [
"id" => $event->getEventId(),
"nameEn" => $event->getName('en'),
"nameAr" => $event->getName('ar')
];
}
}
return ["success" => true, "data" => $response];
}
public function getWeatherPhenomenones()
{
$response = [];
$weatherPhenomenons = new DataObject\PhenomenaList\Listing();
$weatherPhenomenons = $weatherPhenomenons->load();
if ($weatherPhenomenons) {
foreach ($weatherPhenomenons as $weatherPhenomenon) {
$response[] = [
"id" => $weatherPhenomenon->getPhenomenaListId(),
"nameEn" => $weatherPhenomenon->getTitle('en'),
"nameAr" => $weatherPhenomenon->getTitle('ar')
];
}
}
return ["success" => true, "data" => $response];
}
public function getWeatherPhenomenonAffect()
{
$response = [];
$getWeatherPhenomAffects = new DataObject\WeatherPhenomenonAffect\Listing();
$getWeatherPhenomAffects = $getWeatherPhenomAffects->load();
if ($getWeatherPhenomAffects) {
foreach ($getWeatherPhenomAffects as $getWeatherPhenomAffect) {
$response[] = [
"id" => $getWeatherPhenomAffect->getWeatherPhenomenonAffectId(),
"nameEn" => $getWeatherPhenomAffect->getName('en'),
"nameAr" => $getWeatherPhenomAffect->getName('ar')
];
}
}
return ["success" => true, "data" => $response];
}
public function getAlertStatuses($params)
{
$response = [];
$alertStatuss = new DataObject\AlertStatus\Listing();
// Handle search by name
if (isset($params['search']) && !empty($params['search'])) {
$alertStatuss->addConditionParam("name LIKE ?", "%" . $params['search'] . "%");
}
// Handle alert type filter
if (isset($params['alert_id']) && !empty($params['alert_id'])) {
$alertTypeIds = [];
$alertTypeList = new DataObject\AlertType\Listing();
$alertTypeList->addConditionParam("alertTypeId IN (?)", [$params['alert_id']]);
foreach ($alertTypeList as $alertType) {
$alertTypeIds[] = $alertType->getId();
}
$alertStatuss->addConditionParam("alertType__id IN (?)", [$alertTypeIds]);
}
// Check for regionId array and isLandLocked logic
$excludeWavesRising = false;
if (isset($params['regionId']) && is_array($params['regionId']) && count($params['regionId']) > 0) {
foreach ($params['regionId'] as $regionId) {
$region = \Pimcore\Model\DataObject\Region::getByRegionId($regionId, true);
if ($region && $region->getIsLandLocked()) {
$excludeWavesRising = true;
break;
}
}
}
$alertStatuss = $alertStatuss->load();
if ($alertStatuss) {
foreach ($alertStatuss as $alertStatus) {
// Exclude "Waves rising" if needed
if ($excludeWavesRising && ((strtolower(trim($alertStatus->getName('en'))) === 'waves rising'))) {
continue;
}
$alertType = $alertStatus->getAlertType();
$alertData = [];
if (!empty($alertType)) {
$alertData = [
"id" => $alertType->getAlertTypeId(),
"nameEn" => $alertType->getName('en'),
"nameAr" => $alertType->getName('ar')
];
}
$response[] = [
"id" => $alertStatus->getalertStatusId(),
"nameEn" => $alertStatus->getName('en'),
"nameAr" => $alertStatus->getName('ar'),
"imageTemplate" => $alertStatus->getimageTemplate(),
"alertType" => $alertData
];
}
}
return ["success" => true, "data" => $response];
}
public function getGovernorates()
{
$response = [];
$governorates = new DataObject\Governorate\Listing();
$Governorates = $governorates->load();
if ($governorates) {
foreach ($governorates as $governorate) {
$region = $governorate->getregionId();
$regionData = [];
if (!empty($region)) {
$regionData = [
"id" => $region->getRegionId(),
"nameEn" => $region->getName('en'),
"nameAr" => $region->getName('ar'),
"longitude" => $region->getLongitude(),
"latitude" => $region->getLongitude()
];
}
$response[] = [
"id" => $governorate->getgovernoteId(),
"nameEn" => $governorate->getName('en'),
"nameAr" => $governorate->getName('ar'),
"regionId" => $regionData,
"longitude" => $governorate->getLongitude(),
"latitude" => $governorate->getLatitude(),
"isHidden" => $governorate->getisHidden(),
"IsMunicipality" => $governorate->getIsMunicipality(),
"MunicipalityID" => $governorate->getMunicipalityID()
];
}
}
return ["success" => true, "data" => $response];
}
public function getMunicipality($governorateId = null, $lang = 'en')
{
$response = [];
$municipalities = new DataObject\Municipality\Listing();
if (is_array($governorateId)) {
$govIdsArr = [];
foreach ($governorateId as $govId) {
$governorate = \Pimcore\Model\DataObject\Governorate::getByGovernoteId($govId, true);
if ($governorate) {
array_push($govIdsArr, $governorate->getId());
}
}
$municipalities->setCondition("governorate__id IN (" . implode(", ", $govIdsArr) . ")");
} else {
if ($governorateId) {
$governorate = \Pimcore\Model\DataObject\Governorate::getByGovernoteId($governorateId, true);
$municipalities->setCondition("governorate__id = ?", [$governorate->getId()]);
}
}
$municipalities = $municipalities->load();
if ($municipalities) {
foreach ($municipalities as $municipality) {
$response[] = [
"id" => $municipality->getMunicipalityid(),
"nameEn" => $municipality->getName('en'),
"nameAr" => $municipality->getName('ar'),
"longitude" => $municipality->getLongitude(),
"latitude" => $municipality->getLatitude(),
"governate" => $municipality->getGovernorate()->getGovernoteId()
];
}
}
// Determine sorting field based on language
$sortField = 'nameEn'; // Default sorting by English
if (isset($lang) && strtolower($lang) === 'ar') {
$sortField = 'nameAr'; // Sorting by Arabic
}
// Sort manually using usort()
usort($response, function ($a, $b) use ($sortField) {
return strcmp($a[$sortField], $b[$sortField]);
});
return ["success" => true, "data" => $response];
}
public function getMunicipalityByParams($governorateId = null,$search = null, $lang = 'en')
{
$response = [];
$municipalities = new DataObject\Municipality\Listing();
if (is_array($governorateId)) {
$govIdsArr = [];
foreach ($governorateId as $govId) {
$governorate = \Pimcore\Model\DataObject\Governorate::getByGovernoteId($govId, true);
if ($governorate) {
array_push($govIdsArr, $governorate->getId());
}
}
$municipalities->setCondition("governorate__id IN (" . implode(", ", $govIdsArr) . ")");
} else {
if ($governorateId) {
$governorate = \Pimcore\Model\DataObject\Governorate::getByGovernoteId($governorateId, true);
$municipalities->setCondition("governorate__id = ?", [$governorate->getId()]);
}
}
if (isset($search)) {
$municipalities->addConditionParam("name LIKE ?", "%{$search}%");
}
$municipalities = $municipalities->load();
if ($municipalities) {
foreach ($municipalities as $municipality) {
$response[] = [
"id" => $municipality->getMunicipalityid(),
"nameEn" => $municipality->getName('en'),
"nameAr" => $municipality->getName('ar'),
"longitude" => $municipality->getLongitude(),
"latitude" => $municipality->getLatitude(),
"governate" => $municipality->getGovernorate()->getGovernoteId()
];
}
}
// Determine sorting field based on language
$sortField = 'nameEn'; // Default sorting by English
if (isset($lang) && strtolower($lang) === 'ar') {
$sortField = 'nameAr'; // Sorting by Arabic
}
// Sort manually using usort()
usort($response, function ($a, $b) use ($sortField) {
return strcmp($a[$sortField], $b[$sortField]);
});
return ["success" => true, "data" => $response];
}
public function getGovernoratesByRegion($params)
{
$response = [];
$governorates = new DataObject\Governorate\Listing();
if (isset($params['region_id'])) {
$region = \Pimcore\Model\DataObject\Region::getByRegionId($params['region_id'], true);
if (!$region) {
throw new \Exception("Region not available");
}
$governorates->filterByRegionId($region);
}
if (isset($params['region_ids']) && !empty($params['region_ids'])) {
$regionIds = [];
$regionList = new DataObject\Region\Listing();
$regionList->addConditionParam("regionId IN (?)", [$params['region_ids']]);
foreach ($regionList as $region) {
$regionIds[] = $region->getId();
}
$governorates->addConditionParam("regionId__id IN (?)", [$regionIds]);
}
// Load governorates without sorting in Pimcore
$governorates = $governorates->load();
// Convert to array for manual sorting
$count = 0;
if ($governorates) {
foreach ($governorates as $governorate) {
$region = $governorate->getregionId();
$regionData = [];
if (!empty($region)) {
$regionData = [
"id" => $region->getRegionId(),
"nameEn" => $region->getName('en'),
"nameAr" => $region->getName('ar'),
"longitude" => $region->getLongitude(),
"latitude" => $region->getLatitude()
];
}
$response[$count] = [
"id" => $governorate->getgovernoteId(),
"nameEn" => $governorate->getName('en'),
"nameAr" => $governorate->getName('ar'),
"regionId" => $regionData,
"longitude" => $governorate->getLongitude(),
"latitude" => $governorate->getLatitude(),
"isHidden" => $governorate->getisHidden(),
"IsMunicipality" => $governorate->getIsMunicipality(),
"MunicipalityID" => $governorate->getMunicipalityID(),
"bbox" => $governorate->getBbox()
];
if ($governorate->getMunicipalityID() && $governorate->getIsMunicipality()) {
$municipality = \Pimcore\Model\DataObject\Municipality::getBymunicipalityid($governorate->getMunicipalityID(), true);
if ($municipality) {
$muniGovernate = $municipality->getgovernorate();
if ($muniGovernate) {
$response[$count]["parent_id"] = $muniGovernate->getgovernoteId();
$response[$count]["parent_longitude"] = $muniGovernate->getLongitude();
$response[$count]["parent_latitude"] = $muniGovernate->getLatitude();
$response[$count]["parent_name_en"] = $muniGovernate->getName("en");
$response[$count]["parent_name_ar"] = $muniGovernate->getName("ar");
}
}
}
$count++;
}
}
// Determine sorting field based on language
$sortField = 'nameEn'; // Default sorting by English
if (isset($params['lang']) && strtolower($params['lang']) === 'ar') {
$sortField = 'nameAr'; // Sorting by Arabic
}
// Sort manually using usort()
usort($response, function ($a, $b) use ($sortField) {
return strcmp($a[$sortField], $b[$sortField]);
});
return ["success" => true, "data" => $response];
}
public function getGovernoratesByParams($params)
{
$response = [];
$governorates = new DataObject\Governorate\Listing();
if (isset($params['region_id'])) {
$region = \Pimcore\Model\DataObject\Region::getByRegionId($params['region_id'], true);
if (!$region) {
throw new \Exception("Region not available");
}
$governorates->filterByRegionId($region);
}
if (isset($params['region_ids']) && !empty($params['region_ids'])) {
$regionIds = [];
$regionList = new DataObject\Region\Listing();
$regionList->addConditionParam("regionId IN (?)", [$params['region_ids']]);
foreach ($regionList as $region) {
$regionIds[] = $region->getId();
}
$governorates->addConditionParam("regionId__id IN (?)", [$regionIds]);
}
if (isset($params['search'])) {
$governorates->addConditionParam("name LIKE ?", "%{$params['search']}%");
}
// Load governorates without sorting in Pimcore
$governorates = $governorates->load();
// Convert to array for manual sorting
$count = 0;
if ($governorates) {
foreach ($governorates as $governorate) {
$region = $governorate->getregionId();
$regionData = [];
if (!empty($region)) {
$regionData = [
"id" => $region->getRegionId(),
"nameEn" => $region->getName('en'),
"nameAr" => $region->getName('ar'),
"longitude" => $region->getLongitude(),
"latitude" => $region->getLatitude()
];
}
$response[$count] = [
"id" => $governorate->getgovernoteId(),
"nameEn" => $governorate->getName('en'),
"nameAr" => $governorate->getName('ar'),
"regionId" => $regionData,
"longitude" => $governorate->getLongitude(),
"latitude" => $governorate->getLatitude(),
"isHidden" => $governorate->getisHidden(),
"IsMunicipality" => $governorate->getIsMunicipality(),
"MunicipalityID" => $governorate->getMunicipalityID(),
"bbox" => $governorate->getBbox()
];
if ($governorate->getMunicipalityID() && $governorate->getIsMunicipality()) {
$municipality = \Pimcore\Model\DataObject\Municipality::getBymunicipalityid($governorate->getMunicipalityID(), true);
if ($municipality) {
$muniGovernate = $municipality->getgovernorate();
if ($muniGovernate) {
$response[$count]["parent_id"] = $muniGovernate->getgovernoteId();
$response[$count]["parent_longitude"] = $muniGovernate->getLongitude();
$response[$count]["parent_latitude"] = $muniGovernate->getLatitude();
$response[$count]["parent_name_en"] = $muniGovernate->getName("en");
$response[$count]["parent_name_ar"] = $muniGovernate->getName("ar");
}
}
}
$count++;
}
}
// Determine sorting field based on language
$sortField = 'nameEn'; // Default sorting by English
if (isset($params['lang']) && strtolower($params['lang']) === 'ar') {
$sortField = 'nameAr'; // Sorting by Arabic
}
// Sort manually using usort()
usort($response, function ($a, $b) use ($sortField) {
return strcmp($a[$sortField], $b[$sortField]);
});
return ["success" => true, "data" => $response];
}
public function getVersions($notificationObject, $translator)
{
$result = [];
$versions = $notificationObject->getVersions();
if ($versions) {
foreach ($versions as $version) {
$note = $version->getNote();
if ($note == "Update") {
$viewNotification = $version->loadData();
if ($viewNotification instanceof EwsNotification) {
$result[] = $this->createNotificationFormat($viewNotification, $translator);
}
}
}
}
return $result;
}
private function createNotificationFormat($notification, $translator)
{
$response = [];
$critetia = '';
$critetiaAr = '';
$status = 'active';
$alertType = $notification->getAlertType();
$phenomena = $notification->getWeatherPhenomenon();
// Set the timezone to Asia/Riyadh
$timezone = new \DateTimeZone(TIMEZONE);
// Convert start and end dates to Asia/Riyadh timezone
$startDate = $notification->getStartDate() ? $notification->getStartDate()->setTimezone($timezone) : null;
$endDate = $notification->getEndDate() ? $notification->getEndDate()->setTimezone($timezone) : null;
if ($alertType && $phenomena) {
$phenomenaList = $alertType->getPhenomenaList();
if ($phenomenaList) {
$items = $phenomenaList->getItems();
if ($items) {
foreach ($items as $item) {
if ($item->getPhenomena() == $phenomena->getId()) {
$critetia = $item->getCriteria();
$critetiaAr = $item->getCriteriaAr();
break;
}
}
}
}
}
if ($endDate && $endDate < new \DateTime('now', $timezone)) {
$status = "expired";
}
$twentyFourHoursAgo = (new \DateTime('now', $timezone))->modify('-24 hours');
if ($endDate && $endDate < $twentyFourHoursAgo) {
$status = "archived";
}
$response = [
"id" => $notification->getId(),
"searchEwsIdEn" => $notification->getEwsSearchId("en"),
"searchEwsIdAr" => $notification->getEwsSearchId("ar"),
"title" => $startDate ? $startDate->format("dmY") . '-' . $notification->getId() : '',
"alertType" => !empty($notification->getAlertType()) ? $notification->getAlertType()->getAlertTypeId() : "",
"alertTypeAr" => !empty($notification->getAlertType()) ? $notification->getAlertType()->getName("ar") : "",
"alertTypeEn" => !empty($notification->getAlertType()) ? ucwords($notification->getAlertType()->getColor()) : "",
"fromDate" => $startDate ? $startDate->format("Y-m-d H:i:s") : "",
"toDate" => $endDate ? $endDate->format("Y-m-d H:i:s") : "",
"alertStatusID" => !empty($notification->getAlertStatus()) ? $notification->getAlertStatus()->getAlertStatusId() : "",
"alertStatusAr" => !empty($notification->getAlertStatus()) ? $notification->getAlertStatus()->getName("ar") : "",
"alertStatusEn" => !empty($notification->getAlertStatus()) ? $notification->getAlertStatus()->getName("en") : "",
"alertStatusCategory" => "",
"alertHazard" => !empty($notification->getAlertHazard()) ? $this->getAlertHazardArr($notification->getAlertHazard()) : [],
"regionID" => !empty($notification->getRegion()) ? $notification->getRegion()->getRegionId() : "",
"regionAR" => !empty($notification->getRegion()) ? $notification->getRegion()->getName("ar") : "",
"regionEn" => !empty($notification->getRegion()) ? $notification->getRegion()->getName("en") : "",
"governorates" => ($notification->getRegion()) ? $this->getGovernorateDetail($notification->getGovernorate()) : [],
"ewsOtherLocations" => ($notification->getRegion()) ? $this->getGovernorateDetail($notification->getEwsOtherLocations()) : [],
"otherLocationsAr" => $this->getOtherLocationsNames($notification->getEwsOtherLocations(), 'ar'),
"otherLocationsEn" => $this->getOtherLocationsNames($notification->getEwsOtherLocations(), 'en'),
"tweetID" => "",
"enableTwitterNotification" => $notification->getEnableTwitterNotification(),
"enableSMSNotification" => $notification->getEnableSMSNotification(),
"enableEmailNotification" => $notification->getEnableEmailNotification(),
"alertActions" => $this->getAlertActionsByArr($notification->getAlertAction()),
"municipalities" => $this->getMunicipalityArr($notification->getMunicipality()),
"lastModified" => ($notification->getModificationDate()) ? date("Y-m-d H:i:s", $notification->getModificationDate()) : "",
"last_modified_date" => ($notification->getModificationDate()) ? date("Y-m-d", $notification->getModificationDate()) : "",
'coordinates' => $notification->getCoordinates(),
'message' => $notification->getMessage("en"),
"file" => (!empty($notification->getAttachment())) ? API_BASE_URL . $notification->getAttachment()->getFullPath() : [],
'criteria' => $critetia,
'criteriaAr' => $critetiaAr,
'created_at' => ($notification->getCreationDate()) ? date("Y-m-d H:i:s", $notification->getCreationDate()) : "",
'created_by' => ($notification->getUser()) ? $notification->getUser()->getName() : "",
'edited_by' => ($notification->getEditor()) ? $notification->getEditor()->getName() : (($notification->getUser()) ? $notification->getUser()->getName() : ""),
'status_en' => ucfirst($status),
'status_ar' => $translator->trans(ucfirst($status), [], null, 'ar'),
'previewText' => $notification->getPreviewText() ?? false,
];
return $response;
}
private function getAlertHazardArr($alertHazardArr)
{
$result = [];
if ($alertHazardArr) {
foreach ($alertHazardArr as $affect) {
$result[] = [
"pim_id" => $affect->getId(),
"id" => $affect->getAlertHazardId(),
"nameEn" => $affect->getName("en"),
"nameAr" => $affect->getName("ar"),
];
}
}
return $result;
}
private function getAlertActionsByArr($alertActions)
{
$result = [];
if ($alertActions) {
foreach ($alertActions as $alert) {
$result[] = [
"pim_id" => $alert->getId(),
"id" => $alert->getAlertActionId(),
"descriptionEn" => $alert->getName("en"),
"descriptionAr" => $alert->getName("ar"),
];
}
}
return $result;
}
private function getMunicipalityArr($municipalities)
{
$result = [];
if ($municipalities) {
foreach ($municipalities as $municipality) {
// p_R($municipality->getName());
$result[] = [
"id" => $municipality->getMunicipalityId(),
"nameEn" => $municipality->getName("en"),
"nameAr" => $municipality->getName("ar"),
"governate" => $municipality->getGovernorate()->getGovernoteId()
];
}
}
return $result;
}
private function getOtherLocationsNames($otherLocations, $lang = 'ar')
{
$names = []; // Step 1: Initialize an array to hold the names
if ($otherLocations) {
foreach ($otherLocations as $otherLocation) {
$names[] = $otherLocation->getName($lang); // Step 2 & 3: Extract and collect names
}
}
if (empty($names)) { // Check if the names array is empty
return ''; // Return an empty string if there are no names
}
$namesString = implode(', ', $names); // Step 4: Convert the array to a comma-separated string
return $namesString; // Return or use the comma-separated string as needed
}
public function publishedEwsNotification($notificationId, $published, $userGroupIds, $translator, $emailService, $templating, $logger)
{
$result = [];
$viewNotification = DataObject\EwsNotification::getById($notificationId, false);
if (!$viewNotification) {
$viewNotification = DataObject\EwsNotification::getById($notificationId, true);
}
if ($published) {
$viewNotification->setStatus("active");
} else {
$viewNotification->setStatus("");
}
$viewNotification->setPublished($published);
//set ews search Id
$currentDate = new \DateTime();
$formattedDate = $currentDate->format('dmY') . '-' . $viewNotification->getId();
$searchIdEn = 'Early Warning System | ' . $formattedDate . ' | ' . ucfirst($viewNotification->getAlertType()?->getColor()) . ' Alert | ' . $viewNotification->getWeatherPhenomenon()?->getTitle("en");
$searchIdAr = $translator->trans('Early Warning System', [], null, "ar") . ' | ' . $formattedDate . ' | ' . $translator->trans(ucfirst($viewNotification->getAlertType()?->getColor()) . ' Alert', [], null, "ar") . ' | ' . $viewNotification->getWeatherPhenomenon()?->getTitle("ar");
$viewNotification->setEwsSearchId($searchIdEn, "en");
$viewNotification->setEwsSearchId($searchIdAr, "ar");
$viewNotification->save(["versionNote" => "Update"]);
$viewNotification->save();
// $alert = $this->createNotificationFormat($viewNotification, $translator);
if ($published) {
// Ensure you use 'php' to execute the command.
$jsonUserGroupIds = json_encode($userGroupIds);
$process = new Process(['php', 'bin/console', 'app:send-early-warning-alert-email', '--alertId=' . $viewNotification->getId(), '--userGroupIds=' . $jsonUserGroupIds]);
$process->setWorkingDirectory(PIMCORE_PROJECT_ROOT);
try {
$process->mustRun();
$result['success'] = true;
$logger->info("published EwsNotification command executed successfully: " . $process->getOutput());
$result['message'] = $process->getOutput();
} catch (ProcessFailedException $exception) {
$logger->error("published EwsNotification command failed: " . $exception->getMessage());
return ['success' => false, 'message' => $exception->getMessage()];
}
}
return ["success" => true, "message" => $translator->trans("ews_notification_published")];
}
public function reportEwsNotification($param, $translator)
{
$result = [];
$region = null;
try {
$listing = new EwsNotification\Listing();
$reportType = isset($param['report_type']) ? $param['report_type'] : null;
$regionId = isset($param['region_id']) ? $param['region_id'] : null;
if ($regionId) {
$region = \Pimcore\Model\DataObject\Region::getByRegionId($regionId, true);
if (!$region) {
throw new \Exception("Region not exists");
}
}
switch ($reportType) {
case 'published_in_week':
$listing->setCondition("o_published = true AND o_creationDate >= " . strtotime("-1 week"));
break;
case 'published_in_day':
$listing->setCondition("o_published = true AND o_creationDate >= " . strtotime("-1 day"));
break;
case 'published_in_month':
$listing->setCondition("o_published = true AND o_creationDate >= " . strtotime("-1 month"));
break;
case 'published_in_year':
$listing->setCondition("o_published = true AND o_creationDate >= " . strtotime("-1 year"));
break;
case 'published_in_region':
$listing->setCondition("o_published = true AND region__id = ?", [$region->getId()]);
break;
case 'published_in_draft':
$listing->setCondition("o_published = false");
break;
default:
throw new \Exception("Invalid request");
break;
}
$result['count'] = $listing->getCount();
$notifications = $listing->load();
if ($notifications) {
foreach ($notifications as $notification) {
$result['data'][] = $this->createNotificationFormat($notification, $translator);
}
}
return $result;
} catch (\Exception $ex) {
return new \Exception($ex->getMessage());
}
return $result;
}
private function sendEmailNotification($users, $alert, $emailService, $templating)
{
$mailSent = null;
if ($alert) {
$governatesArr = $alert['governorates'];
$governates = [];
if ($governatesArr) {
foreach ($governatesArr as $gov) {
$governates[] = $gov['nameEn'];
}
}
$data = $alert;
$data['sender'] = 'National Center for Meteorology';
//$subject = $alert['searchEwsIdAr'] ??'Severe Weather Alert - ' . $gov['nameEn'];
// $subject = $alert['alertStatusAr'] . ' - ' . $alert['regionAR'];
// $subject = 'النظام الالي للإنذار المبكر :' . ' - ' . $alert['searchEwsIdAr'];
$parts = explode('|', $alert['searchEwsIdAr']);
$excluded = implode('|', array_slice($parts, 1));
$subject = 'النظام الالي للإنذار المبكر :' . $excluded;
// $html = $templating->render('web2print/_manned_alert_notification_ar.html.twig', $data);
//sending an email document (pimcore document)
// $emailAlertTemplate = '/email/alert_notification';
if ($users) {
foreach ($users as $currentUser) {
if (isset($alert['enableEmailNotification']) && $alert['enableEmailNotification']) {
if ($currentUser->getSendEwsEmail() || is_null($currentUser->getSendEwsEmail())) {
# code...
// $email = $currentUser->getEmail();
// $param = ['user' => $currentUser, 'message' => $html, 'url' => null];
// $mailSent = $emailService->sendMail($param, $email, $emailAlertTemplate, $subject);
// $data['name'] = $user->getName();
// extra param js
$alertObj = \Pimcore\Model\DataObject\AlertType::getByAlertTypeId($alert['alertType'], true);
$alertName = $alertObj->getColor() ? $alertObj->getColor() : '';
$alert['user_name'] = $currentUser->getName();
$alert['host'] = API_BASE_URL;
$alert['alertColor'] = $alertName;
$backgroundColor = '#fcb82526';
$borderColor = '#000000';
$textColor = '#000000';
// unsubscribe ews notificaiton token
$tokenURL = '';
$token = $this->userModel->unSubscribeEwsGenerateToken($currentUser->getEmail());
if (!empty($token)) {
$tokenURL = BASE_URL . '/unsubscribe/notification?ews=true&token=' . $token;
}
if (isset($alert['alertColor']) && !empty(trim($alert['alertColor']))) {
$alertColorLower = strtolower(trim($alert['alertColor']));
if ($alertColorLower === 'red') {
$backgroundColor = '#f6000017';
$borderColor = '#F60000';
$textColor = '#F60000';
} elseif ($alertColorLower === 'orange') {
$backgroundColor = '#ff66001f';
$borderColor = '#FF6600';
$textColor = '#FF6600';
} elseif ($alertColorLower === 'yellow') {
$backgroundColor = '#fcb82526';
$borderColor = '#FCB825';
$textColor = '#FCB825';
}
}
$purpose = EWS_MESSAGE;
$alert['backgroundColor'] = $backgroundColor;
$alert['borderColor'] = $borderColor;
$alert['textColor'] = $textColor;
$alert['tokenURL'] = $tokenURL;
$alert['mannedAlertDatailUrl'] = null;
$html = $templating->render('web2print/_manned_alert_notification_ar.html.twig', $alert);
$mailSent = $this->c2Service->sendNotificationEmail($_ENV['EWS_MAIL_TEMPLATE'], $alert['id'], $currentUser->getId(), $html, $subject, $purpose);
// $this->c2Service->sendMannedAlertEmails($html,$currentUser->getId(),$alert['id']);
// $mailSent=$this->c2Service->sendMannedAlertEmails($html,$currentUser->getId(),$alert['id'],$subject);
if ($mailSent) {
$status = "sent";
$this->saveEmailStatus($currentUser->getEmail(), $currentUser->getName(), $alert, $status);
} else {
$status = "not sent";
$this->saveEmailStatus($currentUser->getEmail(), $currentUser->getName(), $alert, $status);
}
}
}
}
}
}
return $mailSent;
}
private function sendExcelEmailNotification($userGroupIds, $alert, $emailService, $templating)
{
$mailSent = null;
if ($alert) {
$governatesArr = $alert['governorates'];
$governates = [];
if ($governatesArr) {
foreach ($governatesArr as $gov) {
$governates[] = $gov['nameEn'];
}
}
$data = $alert;
$data['sender'] = 'National Center for Meteorology';
// $subject = $alert['searchEwsIdAr'] ??'Severe Weather Alert - ' . $gov['nameEn'];
//$subject = $alert['alertStatusAr'] . ' - ' . $alert['regionAR'];
// $subject = 'النظام الالي للإنذار المبكر :' . ' - ' . $alert['searchEwsIdAr'];
$parts = explode('|', $alert['searchEwsIdAr']);
$excluded = implode('|', array_slice($parts, 1));
$subject = 'النظام الالي للإنذار المبكر :' . $excluded;
if ($userGroupIds) {
foreach ($userGroupIds as $userGroupId) {
if ($userGroupId) {
$userGroup = \Pimcore\Model\DataObject\EwsAndReportUserGroup::getById($userGroupId, true);
if ($userGroup instanceof \Pimcore\Model\DataObject\EwsAndReportUserGroup) {
foreach (json_decode($userGroup->getJsonData()) as $currentUser) {
if (isset($currentUser->firstName) && isset($currentUser->lastName) && isset($currentUser->email)) {
// extra param js
$alertObj = \Pimcore\Model\DataObject\AlertType::getByAlertTypeId($alert['alertType'], true);
$alertName = $alertObj->getColor() ? $alertObj->getColor() : '';
$alert['user_name'] = $currentUser->firstName . ' ' . $currentUser->lastName;
$alert['host'] = API_BASE_URL;
$alert['alertColor'] = $alertName;
$backgroundColor = '#fcb82526';
$borderColor = '#000000';
$textColor = '#000000';
if (isset($alert['alertColor']) && !empty(trim($alert['alertColor']))) {
$alertColorLower = strtolower(trim($alert['alertColor']));
if ($alertColorLower === 'red') {
$backgroundColor = '#f6000017';
$borderColor = '#F60000';
$textColor = '#F60000';
} elseif ($alertColorLower === 'orange') {
$backgroundColor = '#ff66001f';
$borderColor = '#FF6600';
$textColor = '#FF6600';
} elseif ($alertColorLower === 'yellow') {
$backgroundColor = '#fcb82526';
$borderColor = '#FCB825';
$textColor = '#FCB825';
}
}
$alert['backgroundColor'] = $backgroundColor;
$alert['borderColor'] = $borderColor;
$alert['textColor'] = $textColor;
$alert['tokenURL'] = null;
$alert['mannedAlertDatailUrl'] = null;
$html = $templating->render('web2print/_manned_alert_notification_ar.html.twig', $alert);
// $email = $currentUser->email;
// $param = ['user' => $currentUser, 'message' => $html, 'url' => null];
// $mailSent = $emailService->sendMail($param, "abdul.muqeet@centric.ae", '/email/alert_notification', $subject);
$purpose = EWS_MESSAGE;
$mailSent = $this->c2Service->sendDefaultEmail($_ENV['EWS_MAIL_TEMPLATE'], $alert['id'], $currentUser->email, $html, $subject, $purpose);
if ($mailSent) {
$status = "sent";
$this->saveEmailStatus($currentUser->email, $currentUser->firstName . ' ' . $currentUser->lastName, $alert, $status);
} else {
$status = "not sent";
$this->saveEmailStatus($currentUser->email, $currentUser->firstName . ' ' . $currentUser->lastName, $alert, $status);
}
}
}
}
}
}
}
}
return $mailSent;
}
private function saveEmailStatus($userEmail, $userName, $alert, $emailStatus)
{
// Get all governorates names in string seprated by ,
$nameEnArray = array_column($alert["governorates"], "nameEn");
$nameEnString = implode(", ", $nameEnArray);
$nameArArray = array_column($alert["governorates"], "nameAr");
$nameArString = implode(", ", $nameArArray);
$ewsEmailStatus = new FetchSentEwsEmail();
$ewsEmailStatus->setParent(\Pimcore\Model\DataObject\Service::createFolderByPath("/Other/FetchSentEwsEmail/"));
$ewsEmailStatus->setKey(\Pimcore\Model\Element\Service::getValidKey($userEmail . "-" . strtotime("now") . "-" . rand(1, 10000), 'object'));
$ewsEmailStatus->setEwsId($alert['id']);
$ewsEmailStatus->setUserName($userName);
$ewsEmailStatus->setEmail($userEmail);
//$ewsEmailStatus->setLocationName($locationName);
$ewsEmailStatus->setAlertType($alert['alertTypeEn'], 'en');
$ewsEmailStatus->setAlertType($alert['alertTypeAr'], 'ar');
$ewsEmailStatus->setAlertStatus($alert['alertStatusEn'], 'en');
$ewsEmailStatus->setAlertStatus($alert['alertStatusAr'], 'ar');
$ewsEmailStatus->setRegionName($alert['regionEn'], 'en');
$ewsEmailStatus->setRegionName($alert['regionAR'], 'ar');
$ewsEmailStatus->setGovernorateNames($nameEnString, 'en');
$ewsEmailStatus->setGovernorateNames($nameArString, 'ar');
$ewsEmailStatus->setStatus($emailStatus);
$ewsEmailStatus->setPublished(true);
$ewsEmailStatus->save();
return $ewsEmailStatus;
}
public function getEwsNotificationEmailStatus($params, $paginator, $translator)
{
$result = [];
try {
$pageSize = isset($params['page_size']) ? $params['page_size'] : LIMIT_PER_PAGE;
$page = isset($params['page']) ? $params['page'] : 1;
$notificationId = $params["id"] ? $params["id"] : null;
$listing = new FetchSentEwsEmail\Listing();
$listing->setCondition("ewsId = ? ", [$notificationId]);
$paginator = $paginator->paginate(
$listing,
$page,
$pageSize
);
if ($paginator->count() > 0) {
foreach ($paginator as $EwsNotificationEmail) {
$result[] = [
"ewsId" => $EwsNotificationEmail->getEwsId(),
"userName" => $EwsNotificationEmail->getUserName(),
"Email" => $EwsNotificationEmail->getEmail(),
"locationName" => $EwsNotificationEmail->getLocationName(),
"alertType" => $EwsNotificationEmail->getAlertType('en'),
"alertTypeAr" => $EwsNotificationEmail->getAlertType('ar'),
"alertStatus" => $EwsNotificationEmail->getAlertStatus('en'),
"alertStatusAr" => $EwsNotificationEmail->getAlertStatus('ar'),
"regionName" => $EwsNotificationEmail->getRegionName('en'),
"regionNameAr" => $EwsNotificationEmail->getRegionName('ar'),
"governorateNames" => explode(",", $EwsNotificationEmail->getGovernorateNames('en')),
"governorateNamesAr" => explode(",", $EwsNotificationEmail->getGovernorateNames('ar')),
"emailStatus" => $EwsNotificationEmail->getStatus(),
"emailStatusAr" => $translator->trans($EwsNotificationEmail->getStatus(), [], null, "ar"),
];
}
}
return ["success" => TRUE, "data" => $result, "paginationVariables" => $paginator->getPaginationData()];
} catch (\Exception $ex) {
return new \Exception($ex->getMessage());
}
return $result;
}
public function getOtherLocations()
{
$response = [];
$otherLocations = new DataObject\OtherLocation\Listing();
$otherLocations = $otherLocations->load();
if ($otherLocations) {
foreach ($otherLocations as $otherLocation) {
$response[] = [
"id" => $otherLocation->getOtherLocationId(),
"nameEn" => $otherLocation->getName('en'),
"nameAr" => $otherLocation->getName('ar')
];
}
}
return ["success" => true, "data" => $response];
}
public function getEwsNotificationByByRegionName($regionName)
{
$db = Db::get();
$selectedLocalities = $db->fetchAll("SELECT * FROM `object_collection_AddressComponents_location` WHERE (`addressKey` = 'locality' || `addressKey` = 'administrative_area_level_1') and (TRIM(REPLACE(`addressValue`,'Province','')) = '" . $regionName . "')");
return $selectedLocalities;
}
public function ewsAnalytics($params, $connection, $lang): array
{
$response = [];
$status = isset($params['status']) ? $params['status'] : "";
$isManned = null;
if (isset($params['isManned']) && $params['isManned'] == true) {
$isManned = true;
} elseif (isset($params['isManned']) && $params['isManned'] == false) {
$isManned = false;
}
if (isset($params['region']) && !empty($params['region'])) {
$region = Region::getByRegionId($params['region'], true);
$response[] = $this->ewsAnalyticsCount($region, $status, $connection, $lang, $isManned);
} else {
$regions = new Region\Listing();
foreach ($regions as $region) {
$response[] = $this->ewsAnalyticsCount($region, $status, $connection, $lang, $isManned);
}
}
return $response;
}
public function ewsAnalyticsCount($region, $status, $connection, $lang, $isManned)
{
$regionNameEn = $region->getName("en");
$regionNameAr = $region->getName("ar");
$statuses = ["active", "archived", "expired"];
$count = ['regionEn' => $regionNameEn, "regionAr" => $regionNameAr];
if (in_array($status, $statuses)) {
$count[$status] = $this->getStatusData($region, $status, $connection, $isManned);
} else {
foreach ($statuses as $s) {
$count[$s] = $this->getStatusData($region, $s, $connection, $isManned);
}
}
return $count;
}
public function getStatusData($region, $status, $connection, $isManned)
{
$totalNotifications = $this->statusCount($region, $status, $isManned);
$alertTypeCount = $this->alertCount($region, $status, $connection, $isManned);
return [
'total_notifications' => $totalNotifications,
'alert_type_count' => $alertTypeCount,
];
}
public function alertCount($region, $status, $connection, $isManned)
{
$currentTimestamp = time(); // Current UNIX timestamp
$twentyFourHoursAgoTimestamp = strtotime('-24 hours'); // 24 hours ago timestamp
$claim_report_sql = $connection->createQueryBuilder();
$claim_report_sql
->select('oa.Color AS color', 'COUNT(oq.oo_id) AS count')
->from('object_ews_notification', 'oq')
->join('oq', 'object_query_alert_type', 'oa', 'oq.alertType__id = oa.oo_id')
->andWhere('oq.region__id = :regionId')
->andWhere('oq.status = :status');
if ($isManned !== null && $isManned == true) {
$claim_report_sql->andWhere('oq.isManned = 1');
} elseif ($isManned !== null && $isManned == false) {
$claim_report_sql->andWhere('oq.isManned = 0');
}
$claim_report_sql->andWhere('oq.o_published = 1'); // added new line
// Initialize parameters array
$params = [
'regionId' => $region->getId(),
'status' => $status,
];
// Add conditions based on status
if ($status == "active") {
$claim_report_sql->andWhere('oq.endDate > :currentTimestamp');
$params['currentTimestamp'] = $currentTimestamp;
} else if ($status == "expired") {
$claim_report_sql->andWhere('oq.endDate < :currentTimestamp AND oq.endDate > :twentyFourHoursAgoTimestamp');
$params['currentTimestamp'] = $currentTimestamp;
$params['twentyFourHoursAgoTimestamp'] = $twentyFourHoursAgoTimestamp;
} else if ($status == "archived") {
$claim_report_sql->andWhere('oq.endDate < :twentyFourHoursAgoTimestamp');
$params['twentyFourHoursAgoTimestamp'] = $twentyFourHoursAgoTimestamp;
}
// Set all parameters at once
$claim_report_sql->setParameters($params);
$claim_report_sql->groupBy('color');
$claimReportstmt = $claim_report_sql->execute();
$results = $claimReportstmt->fetchAllAssociative();
// Fetch all possible colors
$alertTypes = new AlertType\Listing();
$allColors = [];
foreach ($alertTypes as $alertType) {
if ($alertType) {
$allColors[] = $alertType->getColor();
}
}
if (empty($allColors)) {
$allColors = ["yellow", "orange", "red"];
}
// Create an associative array to store counts by color
$countsByColor = [];
foreach ($results as $result) {
$countsByColor[$result['color']] = $result['count'];
}
// Merge counts for existing colors with counts for all colors, including those with count 0
$finalResult = [];
foreach ($allColors as $color) {
$finalResult[] = [
"color" => $color,
"count" => isset($countsByColor[$color]) ? $countsByColor[$color] : 0
];
}
return $finalResult;
}
public function statusCount($region, $status, $isManned)
{
$notifications = new EwsNotification\Listing();
$currentTimestamp = time(); // Get the current UNIX timestamp
$twentyFourHoursAgoTimestamp = strtotime('-24 hours'); // 24 hours ago timestamp
$conditions = "region__id = ? AND status = ?";
$params = [$region->getId(), $status];
if ($status == "active") {
$conditions .= " AND endDate > ?";
$params[] = $currentTimestamp;
} else if ($status == "expired") {
$conditions .= " AND endDate < ? AND endDate > ?";
$params[] = $currentTimestamp;
$params[] = $twentyFourHoursAgoTimestamp;
} else if ($status == "archived") {
$conditions .= " AND endDate < ?";
$params[] = $twentyFourHoursAgoTimestamp;
}
$notifications->addConditionParam($conditions, $params);
// Add condition for manned notifications
if ($isManned !== null) {
$notifications->addConditionParam("isManned = ?", [$isManned]);
}
return $notifications->count();
}
public function searchEwsNotification($params, $lang, $paginator, $translator): array
{
$response = [];
$pageSize = isset($params['page_size']) ? $params['page_size'] : LIMIT_PER_PAGE;
$page = isset($params['page']) ? $params['page'] : 1;
$notificationList = new DataObject\EwsNotification\Listing();
$notificationList->setUnpublished(true);
$notificationList->filterByPublished(true);
if (isset($params['isManned']) && $params['isManned'] == true) {
$notificationList->addConditionParam("isManned = 1");
} elseif (isset($params['isManned']) && $params['isManned'] == false) {
$notificationList->addConditionParam("isManned = 0");
}
if (isset($params['id']) && !empty($params['id'])) {
$idz = $params['id'];
$notificationList->addConditionParam("oo_id IN (?)", [$idz]);
}
if (isset($params['alertAction']) && !empty($params['alertAction'])) {
$alertActionIds = [];
$alertActionList = new DataObject\AlertAction\Listing();
$alertActionList->addConditionParam("alertActionId IN (?)", [$params['alertAction']]);
foreach ($alertActionList as $alertAction) {
$alertActionIds[] = $alertAction->getId();
}
$alertActionids = implode(",", $alertActionIds);
$notificationList->addConditionParam("alertAction REGEXP CONCAT('(^|,)(', REPLACE('$alertActionids',',', '|'), ')(,|$)')");
}
if (isset($params['alertType']) && !empty($params['alertType'])) {
$alertTypeIds = [];
$alertTypeList = new DataObject\AlertType\Listing();
$alertTypeList->addConditionParam("alertTypeId IN (?)", [$params['alertType']]);
foreach ($alertTypeList as $alertType) {
$alertTypeIds[] = $alertType->getId();
}
$notificationList->addConditionParam("alertType__id IN (?)", [$alertTypeIds]);
}
// if (isset($params['phenomena']) && !empty($params['phenomena'])) {
// $phenomenaIds = [];
// $phenomenaList = new DataObject\PhenomenaList\Listing();
// $phenomenaList->addConditionParam("phenomenalistid IN (?)", [$params['phenomena']]);
// foreach ($phenomenaList as $phenomena) {
// $phenomenaIds[] = $phenomena->getId();
// }
// $notificationList->addConditionParam("weatherPhenomenon__id IN (?)", [$phenomenaIds]);
// }
if (!empty($params['phenomena'])) {
$alertStatusSql = null;
foreach ($params['phenomena'] as $alertStatus) {
$alertStatus = \Pimcore\Model\DataObject\AlertStatus::getByAlertStatusId($alertStatus, true);
if ($alertStatus) {
$alertStatusSql .= "alertStatus__id = " . $alertStatus->getId() . " OR ";
}
}
$notificationList->addConditionParam("(" . substr($alertStatusSql, 0, -3) . ")");
}
if (isset($params['region']) && !empty($params['region'])) {
$regionIds = [];
$regionList = new DataObject\Region\Listing();
$regionList->addConditionParam("regionId IN (?)", [$params['region']]);
foreach ($regionList as $region) {
$regionIds[] = $region->getId();
}
$notificationList->addConditionParam("region__id IN (?)", [$regionIds]);
}
if (isset($params['governate']) && !empty($params['governate'])) {
$governatesIds = [];
$governateList = new DataObject\Governorate\Listing();
$governateList->addConditionParam("governoteId IN (?)", [$params['governate']]);
foreach ($governateList as $governate) {
$governatesIds[] = $governate->getId();
}
$governatesIds = implode(",", $governatesIds);
$notificationList->addConditionParam("governorate REGEXP CONCAT('(^|,)(', REPLACE('$governatesIds',',', '|'), ')(,|$)')");
}
if (isset($params['status'][0]) && !empty($params['status'][0])) {
$currentTimestamp = time();
$twentyFourHoursAgo = strtotime('-24 hours');
if ($params['status'][0] == "active" && (!isset($params['status'][1]) || empty($params['status'][1]))) {
// Filter notifications with an end date in the future or equal to current time
$notificationList->filterByEndDate($currentTimestamp, ">=");
} else if ($params['status'][0] == "expired" && (!isset($params['status'][1]) || empty($params['status'][1]))) {
// Filter notifications with an end date in the past, but not older than 24 hours
$notificationList->filterByEndDate($currentTimestamp, "<");
$notificationList->filterByEndDate($twentyFourHoursAgo, ">=");
} else if ($params['status'][0] == "archived" && (!isset($params['status'][1]) || empty($params['status'][1]))) {
// Filter notifications with an end date older than 24 hours
$notificationList->filterByEndDate($twentyFourHoursAgo, "<");
} else if (isset($params['status'][1]) && !empty($params['status'][1])) {
if (($params['status'][0] == "active" && $params['status'][1] == "expired") || ($params['status'][0] == "expired" && $params['status'][1] == "active")) {
// Filter notifications that are either active or expired
$notificationList->filterByEndDate($currentTimestamp, ">=");
$notificationList->filterByEndDate($twentyFourHoursAgo, ">=");
}
}
} else {
// If no status is provided, return 0 records
$notificationList->addConditionParam("1 = 0");
}
$notificationList->setLocale($lang);
if (isset($params['searchId']) && !empty($params['searchId'])) {
$notificationList->addConditionParam(
"(ewsSearchId LIKE ?)",
[
'%' . $params['searchId'] . '%'
]
);
}
if (isset($params['alertHazard']) && !empty($params['alertHazard'])) {
$alertHazardIds = [];
$alertHazardList = new DataObject\AlertHazard\Listing();
$alertHazardList->addConditionParam("alertHazardId IN (?)", [$params['alertHazard']]);
foreach ($alertHazardList as $alertHazard) {
$alertHazardIds[] = $alertHazard->getId();
}
$alertHazardIds = implode(",", $alertHazardIds);
$notificationList->addConditionParam("alertHazard REGEXP CONCAT('(^|,)(', REPLACE('$alertHazardIds',',', '|'), ')(,|$)')");
}
if (isset($params['municipality']) && !empty($params['municipality'])) {
$municipalityIds = [];
$municipalityList = new DataObject\Municipality\Listing();
$municipalityList->addConditionParam("municipalityid IN (?)", [$params['municipality']]);
foreach ($municipalityList as $municipality) {
$municipalityIds[] = $municipality->getId();
}
$municipalityIds = implode(",", $municipalityIds);
$notificationList->addConditionParam("municipality REGEXP CONCAT('(^|,)(', REPLACE('$municipalityIds',',', '|'), ')(,|$)')");
}
if (isset($params['startDate']) && !empty($params['startDate'])) {
$notificationList->filterByStartDate(strtotime($params['startDate']), ">=");
}
if (isset($params['endDate']) && !empty($params['endDate'])) {
$notificationList->filterByEndDate(strtotime($params['endDate']), "<=");
}
if (isset($params['fromDate']) && isset($params['toDate']) && !empty($params['fromDate']) && !empty($params['toDate'])) {
$fromDate = new \DateTime($params['fromDate']);
$toDate = new \DateTime($params['toDate']);
// Ensure the dates are in the correct format
$fromDateStr = strtotime($fromDate->format('Y-m-d H:i:s'));
$toDateStr = strtotime($toDate->format('Y-m-d') . ' 23:59:59');
$notificationList->addConditionParam(
"(o_creationDate >= ? AND o_creationDate <= ?)",
[$fromDateStr, $toDateStr]
);
}
$notifications = $notificationList->load();
$sortedData = [];
foreach ($notifications as $notification) {
$regionEn = $notification->getRegion()->getName("en"); // Assuming getRegion() is available
$startDate = $notification->getStartDate()->format('Y-m-d H:i:s'); // Assuming getStartDate() returns a \DateTime
$endDate = $notification->getEndDate()->format('Y-m-d H:i:s');
$alertStatusEn = $notification->getWeatherPhenomenon()?->getTitle("en");
$creationDate = $notification->getCreationDate(); // Assuming getCreationDate() returns a \DateTime
$searchIdEn = $notification->getEwsSearchId("en");
$searchIdAr = $notification->getEwsSearchId("ar");
$title = $notification->getStartDate() ? $notification->getStartDate()->format("dmY") . '-' . $notification->getId() : '';
$alertTypeEn = $notification->getAlertType()?->getName("en");
$fromDate = $notification->getStartDate()->format('Y-m-d H:i:s');
$toDate = $notification->getEndDate()->format('Y-m-d H:i:s');
$region = $regionEn;
$created_at = $notification->getCreationDate();
$alertStatus = $alertStatusEn;
$sortedData[] = [
'notification' => $notification,
'regionName' => $regionEn,
'alertStatus' => $alertStatusEn,
'startDate' => $startDate,
'endDate' => $endDate,
'creationDate' => $creationDate, // Add creation date to sorting criteria
'searchIdEn' => $searchIdEn,
'searchIdAr' => $searchIdAr,
'title' => $title,
'alertType' => $alertTypeEn,
'fromDate' => $fromDate,
'toDate' => $toDate,
'region' => $region,
'created_at' => $created_at,
'alertStatus' => $alertStatus
];
}
// Define default sort orders and detect if any sort parameter is provided
$sortOrderRegion = $params['sortByRegion'] ?? null;
$sortOrderStartDate = $params['sortByStartDate'] ?? null;
$sortOrderEndDate = $params['sortByEndDate'] ?? null;
$sortOrderAlertStatus = $params['sortByAlertStatus'] ?? null;
$sortOrderSearchIdEn = $params['sortBySearchIdEn'] ?? null;
$sortOrderSearchIdAr = $params['sortBySearchIdAr'] ?? null;
$sortOrderCreatedAt = $params['sortByCreated'] ?? null;
$sortOrderTitle = $params['sortByTitle'] ?? null;
$sortOrderAlertType = $params['sortByAlertType'] ?? null;
$sortOrderFromDate = $params['sortByFromDate'] ?? null;
$sortOrderToDate = $params['sortByToDate'] ?? null;
$sortOrderRegionNew = $params['sortByRegionNew'] ?? null;
$sortOrderCreatedAtNew = $params['sortByCreatedAt'] ?? null;
$sortOrderAlertStatusNew = $params['sortByAlertStatusNew'] ?? null;
// Support for orderKey and order parameters (NEW - clean approach)
$orderKey = $params['orderKey'] ?? null;
$order = $params['order'] ?? 'asc';
// Simple mapping for new fields
$newFieldMapping = [
'title' => 'sortOrderTitle',
'alertType' => 'sortOrderAlertType',
'fromDate' => 'sortOrderFromDate',
'toDate' => 'sortOrderToDate',
'region' => 'sortOrderRegionNew',
'created_at' => 'sortOrderCreatedAtNew',
'alertStatus' => 'sortOrderAlertStatusNew'
];
// Set the appropriate sort order variable
if ($orderKey && isset($newFieldMapping[$orderKey])) {
$variableName = $newFieldMapping[$orderKey];
$$variableName = $order;
}
// Check if any sort parameter is provided (OLD + NEW)
$anySortParamProvided = $sortOrderRegion || $sortOrderStartDate || $sortOrderEndDate || $sortOrderAlertStatus || $sortOrderSearchIdEn || $sortOrderSearchIdAr || $sortOrderTitle || $sortOrderAlertType || $sortOrderFromDate || $sortOrderToDate || $sortOrderRegionNew || $sortOrderCreatedAtNew || $sortOrderAlertStatusNew;
usort($sortedData, function ($a, $b) use ($sortOrderRegion, $sortOrderStartDate, $sortOrderEndDate, $sortOrderAlertStatus, $sortOrderSearchIdEn, $sortOrderSearchIdAr, $sortOrderCreatedAt, $sortOrderTitle, $sortOrderAlertType, $sortOrderFromDate, $sortOrderToDate, $sortOrderRegionNew, $sortOrderCreatedAtNew, $sortOrderAlertStatusNew, $anySortParamProvided) {
if (!$anySortParamProvided || $sortOrderCreatedAt) {
if ($sortOrderCreatedAt == null) {
$sortOrderCreatedAt = "desc";
}
// Default to sorting by creation date if no sort parameter is provided
$compareCreatedAt = strcmp($a['creationDate'], $b['creationDate']) * ($sortOrderCreatedAt === 'desc' ? -1 : 1);
if ($compareCreatedAt !== 0) return $compareCreatedAt; // Assuming 'asc' as default sort order for creation date
}
// Else, sort based on the provided parameters
if ($sortOrderRegion) {
$compareRegion = strcmp($a['regionName'], $b['regionName']) * ($sortOrderRegion === 'desc' ? -1 : 1);
if ($compareRegion !== 0) return $compareRegion;
}
if ($sortOrderSearchIdEn) {
$compareSearchIdEn = strcmp($a['searchIdEn'], $b['searchIdEn']) * ($sortOrderSearchIdEn === 'desc' ? -1 : 1);
if ($compareSearchIdEn !== 0) return $compareSearchIdEn;
}
if ($sortOrderSearchIdAr) {
$compareSearchIdAr = strcmp($a['searchIdAr'], $b['searchIdAr']) * ($sortOrderSearchIdAr === 'desc' ? -1 : 1);
if ($compareSearchIdAr !== 0) return $compareSearchIdAr;
}
if ($sortOrderAlertStatus) {
$compareAlertStatus = strcmp($a['alertStatus'], $b['alertStatus']) * ($sortOrderAlertStatus === 'desc' ? -1 : 1);
if ($compareAlertStatus !== 0) return $compareAlertStatus;
}
if ($sortOrderStartDate) {
$compareStartDate = strcmp($a['startDate'], $b['startDate']) * ($sortOrderStartDate === 'desc' ? -1 : 1);
if ($compareStartDate !== 0) return $compareStartDate;
}
if ($sortOrderEndDate) {
return strcmp($a['endDate'], $b['endDate']) * ($sortOrderEndDate === 'desc' ? -1 : 1);
}
// New sorting fields (ADDED - keeps old functionality)
if ($sortOrderTitle) {
$compareTitle = strcmp($a['title'], $b['title']) * ($sortOrderTitle === 'desc' ? -1 : 1);
if ($compareTitle !== 0) return $compareTitle;
}
if ($sortOrderAlertType) {
$compareAlertType = strcmp($a['alertType'], $b['alertType']) * ($sortOrderAlertType === 'desc' ? -1 : 1);
if ($compareAlertType !== 0) return $compareAlertType;
}
if ($sortOrderFromDate) {
$compareFromDate = strcmp($a['fromDate'], $b['fromDate']) * ($sortOrderFromDate === 'desc' ? -1 : 1);
if ($compareFromDate !== 0) return $compareFromDate;
}
if ($sortOrderToDate) {
$compareToDate = strcmp($a['toDate'], $b['toDate']) * ($sortOrderToDate === 'desc' ? -1 : 1);
if ($compareToDate !== 0) return $compareToDate;
}
if ($sortOrderRegionNew) {
$compareRegionNew = strcmp($a['region'], $b['region']) * ($sortOrderRegionNew === 'desc' ? -1 : 1);
if ($compareRegionNew !== 0) return $compareRegionNew;
}
if ($sortOrderCreatedAtNew) {
$compareCreatedAtNew = strcmp($a['created_at'], $b['created_at']) * ($sortOrderCreatedAtNew === 'desc' ? -1 : 1);
if ($compareCreatedAtNew !== 0) return $compareCreatedAtNew;
}
if ($sortOrderAlertStatusNew) {
$compareAlertStatusNew = strcmp($a['alertStatus'], $b['alertStatus']) * ($sortOrderAlertStatusNew === 'desc' ? -1 : 1);
if ($compareAlertStatusNew !== 0) return $compareAlertStatusNew;
}
// If all provided parameters are equal, or no specific sort orders are provided, default to creation date
return ($b['creationDate'] ?? 0) - ($a['creationDate'] ?? 0);
});
$sortedNotifications = array_map(function ($item) {
return $item['notification'];
}, $sortedData);
if (isset($params['dashboard']) && !empty($params['dashboard'] && $params['dashboard'] == 'dashboard')) {
return ["data" => $notificationList];
}
// Extract the sorted notifications
if ($paginator == null) {
// if ($sortedNotifications->count()) {
foreach ($sortedNotifications as $notification) {
// if($notification->getPublished())
$response[] = $this->createNotificationFormat($notification, $translator);
}
// }
return ["success" => TRUE, "data" => $response];
}
$paginator = $paginator->paginate(
$sortedNotifications,
$page,
$pageSize
);
// if ($sortedNotifications->count()) {
foreach ($paginator as $notification) {
// if($notification->getPublished())
$response[] = $this->createNotificationFormat($notification, $translator);
}
// }
return ["data" => $response, "paginationVariables" => $paginator->getPaginationData()];
}
public function archiveNotification($params, $translator): array
{
$id = $params['id'] ?? null;
if (!$id) {
throw new \Exception("EWS id is required");
}
$ewsNotification = \Pimcore\Model\DataObject::getById($id);
if (!$ewsNotification instanceof \Pimcore\Model\DataObject\EwsNotification) {
// throw new \Exception("Ews notification not found");
return ['success' => false, 'message' => $translator->trans('ews_notification_not_found')];
}
if (isset($params['status']) && $params['status']) {
$ewsNotification->setStatus("archived");
}
$ewsNotification->save(["versionNote" => "Update"]);
return ['success' => true, 'message' => $translator->trans('archive_ews_notification'), "notification_id" => $ewsNotification->getId()];
}
public function getId(): ?UuidV4
{
$uuid = UuidV4::v4();
return $uuid;
}
public function getPhenomenaList()
{
$phenomenas = new \Pimcore\Model\DataObject\PhenomenaList\Listing();
$phenomenas->setOrderKey("o_creationDate");
$phenomenas->setOrder("desc");
$phenomenas->load();
$response = [];
if (count($phenomenas) > 0) {
foreach ($phenomenas as $phenomena) {
$response[] = [
"id" => $phenomena->getPhenomenaListId(),
"nameEN" => $phenomena->getTitle('en'),
"nameAr" => $phenomena->getTitle('ar'),
];
}
return ["success" => true, "data" => $response];
}
return ["success" => false, "data" => $response];
}
public function getHazardListByAlertStatusId($statusId, $lang = "en")
{
$response = [];
$alertSttaus = \Pimcore\Model\DataObject\AlertStatus::getByAlertStatusId($statusId, true);
if ($alertSttaus instanceof \Pimcore\Model\DataObject\AlertStatus) {
if ($alertSttaus && $alertSttaus->getAlertHazards()) {
foreach ($alertSttaus->getAlertHazards() as $value) {
$alertHazardObj = $value->getLocalizedfields()->getItems();
$response[] = ["id" => (int)$value->getAlertHazardId(), "nameEn" => $alertHazardObj['en']['name'], "nameAr" => $alertHazardObj['ar']['name']];
}
} else {
return ["success" => false, "message" => "No Hazard is set"];
}
} else {
return ["success" => false, "message" => "Invalid alert status id"];
}
return ["success" => true, "data" => $response];
}
// public function getHazardListByAlertStatusId($statusId, $lang = "en")
// {
// $response = [];
// $alertPhenomena = \Pimcore\Model\DataObject\PhenomenaList::getByPhenomenaListId($statusId, true);
// if ($alertPhenomena instanceof \Pimcore\Model\DataObject\PhenomenaList) {
// if ($alertPhenomena && $alertPhenomena->getAlertHazards()) {
// foreach ($alertPhenomena->getAlertHazards() as $value) {
// $alertHazardObj = $value->getLocalizedfields()->getItems();
// $response[] = ["id" => (int)$value->getAlertHazardId(), "nameEn" => $alertHazardObj['en']['name'], "nameAr" => $alertHazardObj['ar']['name']];
// }
// } else {
// return ["success" => false, "message" => "No Hazard is set"];
// }
// } else {
// return ["success" => false, "message" => "Invalid alert status id"];
// }
// return ["success" => true, "data" => $response];
// }
public function getOtherGovernoratesByRegion($regionId)
{
$response = [];
$region = \Pimcore\Model\DataObject\Region::getByRegionId($regionId, true);
if (!$region) {
throw new \Exception("Region not available");
}
$otherGovernorates = new DataObject\EwsOtherLocation\Listing();
//$otherGovernorates->filterByRegionId($region);
$otherGovernorates = $otherGovernorates->load();
if ($otherGovernorates) {
foreach ($otherGovernorates as $governorate) {
$region = $governorate->getregionId();
$regionData = [];
if (!empty($region)) {
$regionData = [
"id" => $region->getRegionId(),
"nameEn" => $region->getName('en'),
"nameAr" => $region->getName('ar'),
"longitude" => $region->getLongitude(),
"latitude" => $region->getLongitude()
];
}
$response[] = [
"id" => $governorate->getgovernoteId(),
"nameEn" => $governorate->getName('en'),
"nameAr" => $governorate->getName('ar'),
"regionId" => $regionData,
"longitude" => $governorate->getLongitude(),
"latitude" => $governorate->getLatitude(),
"isHidden" => $governorate->getisHidden(),
"IsMunicipality" => $governorate->getIsMunicipality(),
"MunicipalityID" => $governorate->getMunicipalityID()
];
}
}
return ["success" => true, "data" => $response];
}
public function createEwsReportUserGroup($params, $translator)
{
$response = [];
$checkGroup = EwsAndReportUserGroup::getByName($params['name'], true);
if ($checkGroup instanceof EwsAndReportUserGroup) {
return ["success" => false, "message" => $translator->trans("group_name_already_exists"), "name" => $params['name']];
}
$ewsReportUserGroup = new DataObject\EwsAndReportUserGroup();
$ewsReportUserGroup->setParent(\Pimcore\Model\DataObject\Service::createFolderByPath("/Notification/userGroups/" . $params['type'] . "/"));
$ewsReportUserGroup->setKey(\Pimcore\Model\Element\Service::getValidKey($params['name'] . "-" . strtotime("now") . "-" . rand(1, 10000), 'object', 'object'));
$ewsReportUserGroup->setName(strip_tags($params['name']));
$ewsReportUserGroup->setJsonData(json_encode($params['data']));
$ewsReportUserGroup->setGroupType($params['type']);
$ewsReportUserGroup->setPublished(true);
$ewsReportUserGroup->save();
return ["success" => true, "message" => $translator->trans("ews_report_user_group_created")];
}
public function updateEwsReportUserGroup($params, $translator)
{
$response = [];
$updateGroup = EwsAndReportUserGroup::getById($params['id']);
if (!$updateGroup instanceof EwsAndReportUserGroup) {
return ["success" => false, "message" => $translator->trans('ews_report_user_group_not_found'), "id" => $params['id']];
}
if (isset($params['name']) && !empty($params['name']) && $updateGroup->getName() != $params['name']) {
$checkGroup = EwsAndReportUserGroup::getByName($params['name'], true);
if ($checkGroup instanceof EwsAndReportUserGroup) {
return ["success" => false, "message" => $translator->trans("group_name_already_exists"), "name" => $params['name']];
}
$updateGroup->setName(strip_tags($params['name']));
$updateGroup->setKey(\Pimcore\Model\Element\Service::getValidKey($params['name'] . "-" . strtotime("now") . "-" . rand(1, 10000), 'object', 'object'));
}
if (isset($params['data']) && !empty($params['data'])) {
$updateGroup->setJsonData(json_encode($params['data']));
}
if (isset($params['type']) && !empty($params['type'])) {
$updateGroup->setGroupType($params['type']);
$updateGroup->setParent(\Pimcore\Model\DataObject\Service::createFolderByPath("/Notification/userGroups/" . $params['type'] . "/"));
}
$updateGroup->setJsonData(json_encode($params['data']));
$updateGroup->setGroupType($params['type']);
$updateGroup->setPublished(true);
$updateGroup->save();
return ["success" => true, "message" => $translator->trans("ews_report_user_group_updated")];
}
public function deleteEwsReportUserGroup($params, $translator)
{
$response = [];
$deleteGroup = EwsAndReportUserGroup::getById($params['id']);
if (!$deleteGroup instanceof EwsAndReportUserGroup) {
return ["success" => false, "message" => $translator->trans('ews_report_user_group_not_found'), "id" => $params['id']];
}
$deleteGroup->delete();
return ["success" => true, "message" => $translator->trans("ews_report_user_group_deleted")];
}
public function listEwsReportUserGroup($params, $paginator, $translator)
{
$data = [];
$listing = new EwsAndReportUserGroup\Listing();
// Allowed sorting keys
$allowedOrderKeys = ['name', 'type', 'email_count', 'oo_id'];
$allowedOrderDirections = ['asc', 'desc'];
$orderKey = $params['orderKey'] ?? 'oo_id';
$orderDirection = strtolower($params['order'] ?? 'desc');
if (in_array($orderKey, $allowedOrderKeys) && in_array($orderDirection, $allowedOrderDirections)) {
$fieldMapping = [
'name' => 'name',
'type' => 'groupType',
'oo_id' => 'oo_id'
];
// Normal sorting keys (done in SQL)
if (isset($fieldMapping[$orderKey])) {
$listing->setOrderKey($fieldMapping[$orderKey]);
$listing->setOrder(strtoupper($orderDirection));
}
} else {
// Default sorting
$orderKey = 'oo_id';
$orderDirection = 'desc';
$listing->setOrderKey('oo_id');
$listing->setOrder('DESC');
}
if (isset($params['type']) && !empty($params['type'])) {
$listing->addConditionParam("groupType = ?", [$params['type']]);
}
if (isset($params['search']) && !empty($params['search'])) {
$listing->addConditionParam("name LIKE ? ", ['%' . $params['search'] . '%']);
}
$pageSize = isset($params['page_size']) ? $params['page_size'] : LIMIT_PER_PAGE;
$page = isset($params['page']) ? $params['page'] : 1;
$paginator = $paginator->paginate(
$listing,
$page,
$pageSize
);
// Convert paginator to array
$groups = iterator_to_array($paginator);
// Handle email_count sorting manually in PHP
if ($orderKey === 'email_count') {
usort($groups, function ($a, $b) use ($orderDirection) {
$lenA = count(json_decode($a->getJsonData(), true) ?? []);
$lenB = count(json_decode($b->getJsonData(), true) ?? []);
return $orderDirection === 'asc' ? $lenA <=> $lenB : $lenB <=> $lenA;
});
}
// Prepare output data
foreach ($groups as $group) {
$jsonData = json_decode($group->getJsonData(), true) ?? [];
$data[] = [
"id" => $group->getId(),
"name" => $group->getName(),
"type" => $group->getGroupType(),
"email_count" => count($jsonData),
"data" => $jsonData
];
}
if (count($data) > 0) {
return ["success" => true, "data" => $data, "paginationVariables" => $paginator->getPaginationData()];
} else {
return ["success" => false, "message" => $translator->trans('no_ews_report_user_group_found')];
}
}
public function getSortCriteria()
{
// This is a placeholder; you'll need to adapt this based on how you can access the region's name or other criteria
return $this->getRegion()->getName();
}
public function getCenters($governorateId = null, $lang = 'en')
{
$response = [];
$districts = new DataObject\District\Listing();
if (is_array($governorateId)) {
$govIdsArr = [];
foreach ($governorateId as $govId) {
$governorate = \Pimcore\Model\DataObject\Governorate::getByGovernoteId($govId, true);
if ($governorate) {
array_push($govIdsArr, $governorate->getId());
}
}
$districts->setCondition("governorate__id IN (" . implode(", ", $govIdsArr) . ")");
} else {
if ($governorateId) {
$governorate = \Pimcore\Model\DataObject\Governorate::getByGovernoteId($governorateId, true);
$districts->setCondition("governorate__id = ?", [$governorate->getId()]);
}
}
$districts = $districts->load();
if ($districts) {
foreach ($districts as $district) {
$response[] = [
"id" => $district->getObjectId(),
"nameEn" => $district->getName('en'),
"nameAr" => $district->getName('ar'),
"longitude" => $district->getLongitude(),
"latitude" => $district->getLatitude(),
"governate" => $district->getGovernorate()->getGovernoteId()
];
}
}
// Determine sorting field based on language
$sortField = 'nameEn'; // Default sorting by English
if (isset($lang) && strtolower($lang) === 'ar') {
$sortField = 'nameAr'; // Sorting by Arabic
}
// Sort manually using usort()
usort($response, function ($a, $b) use ($sortField) {
return strcmp($a[$sortField], $b[$sortField]);
});
return ["success" => true, "data" => $response];
}
}