<?php
namespace App\EventSubscriber;
use Carbon\Carbon;
use Pimcore\Mail;
use Pimcore\Model\DataObject;
use Pimcore\Event\Model\DataObjectEvent;
use Pimcore\Model\DataObject\EwsNotification;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use App\Service\TwitterService;
use App\C2IntegrationBundle\Service\C2Service;
use Pimcore\Log\ApplicationLogger;
class TwitterEwsEndEventListner
{
private TwitterService $twitterService;
private C2Service $c2Service;
private ApplicationLogger $logger;
/**
* Alert ids already handled in this request. The listener saves the object after tweeting,
* which re-fires pimcore.dataobject.postUpdate; without this guard it would re-enter and
* post a duplicate tweet (rejected by Twitter as duplicate content).
*/
private static array $processedInRequest = [];
public function __construct(ApplicationLogger $logger)
{
$this->twitterService = new TwitterService();
$this->c2Service = new C2Service();
$this->logger = $logger;
}
public function onObjectUpdate(DataObjectEvent $ewsNotificationObject)
{
$ewsNotification = $ewsNotificationObject->getObject();
// DIAGNOSTIC (temporary): log the gate values on every EWS save so we can see
// why the End tweet is skipped. Remove once the End-tweet issue is resolved.
if ($ewsNotification instanceof EwsNotification) {
$this->logger->info(sprintf(
'[END-DIAG] EndTweetListener fired for EWS ID %s | published=%s | enableTwitter=%s | status=%s',
$ewsNotification->getId(),
var_export($ewsNotification->isPublished(true), true),
var_export($ewsNotification->getEnableTwitterNotification(), true),
var_export($ewsNotification->getStatus(), true)
));
}
if (
($ewsNotification instanceof EwsNotification) &&
($ewsNotification->isPublished(true)) &&
$ewsNotification->getEnableTwitterNotification() == true &&
$ewsNotification->getStatus() === "ended"
) {
// Prevent re-entry from the $ewsNotification->save() below re-firing postUpdate.
$ewsId = $ewsNotification->getId();
if (isset(self::$processedInRequest[$ewsId])) {
return;
}
self::$processedInRequest[$ewsId] = true;
$this->logger->info("[END-DIAG] Gate passed, entering End tweet flow for EWS ID: {$ewsId}");
try {
// Twitter rejects duplicate status text, so the caption must be unique per alert.
// The early-warning URL carries the alert id, guaranteeing uniqueness.
$HashTagcontent = trim(
"#alertEnd\n"
. ($ewsNotification->getEwsSearchId('ar') ? $ewsNotification->getEwsSearchId('ar') . "\n" : '')
. 'https://beta.ncm.gov.sa/en/early-warning/' . $ewsId
);
// Post the browser-rendered image persisted on the alert (endXAttachment, set
// from x_img by the end action). If it's missing there is nothing to tweet.
$asset = $ewsNotification->getEndXAttachment();
if (!$asset instanceof \Pimcore\Model\Asset) {
$this->logger->error("[END-DIAG] No endXAttachment image for EWS ID: {$ewsId}; skipping tweet.");
return;
}
$this->logger->info("[END-DIAG] Using persisted endXAttachment asset id {$asset->getId()} for EWS ID: {$ewsId}");
$asset_path = PIMCORE_PROJECT_ROOT . '/public/var/assets' . $asset->getPath() . $asset->getFileName();
$this->logger->info("[END-DIAG] Asset created at {$asset_path} (exists=" . var_export(is_file($asset_path), true) . ") for EWS ID: {$ewsId}");
$this->logger->info("[END-DIAG] Calling Twitter uploadMedia for EWS ID: {$ewsId}");
$tweet = $this->twitterService->uploadMedia($asset_path, $HashTagcontent);
$this->logger->info("[END-DIAG] uploadMedia returned (httpCode=" . ($tweet['httpCode'] ?? 'n/a') . ") for EWS ID: {$ewsId}");
if ($tweet) {
if (isset($tweet['result']->data)) {
$tweet_text = $tweet['result']?->data?->text;
preg_match('/https?:\/\/\S+/', $tweet_text, $matches);
$url = $matches[0] ?? null;
$this->c2Service->addAsset([$asset], $url);
}
if (!empty($tweet['tweetId'])) {
$ewsNotification->setTwitterId($tweet['tweetId']);
}
$ewsNotification->setTwitterLog($tweet['data']);
$ewsNotification->save();
$logContext = [
'ewsId' => $ewsNotification->getId(),
'tweetId' => $tweet['tweetId'] ?? null,
'httpCode' => $tweet['httpCode'],
'response' => $tweet['data']
];
if (in_array($tweet['httpCode'], [200, 201, 204])) {
$this->logger->info("Twitter post successful for EWS ID: {$ewsNotification->getId()}", $logContext);
} elseif ($tweet['httpCode'] === 403) {
$responseData = json_decode($tweet['data'], true);
$errorMessage = $responseData['detail'] ?? 'Forbidden';
$this->logger->error("Twitter post failed (403) for EWS ID: {$ewsNotification->getId()} - $errorMessage", $logContext);
} else {
$this->logger->error("Twitter post failed (HTTP {$tweet['httpCode']}) for EWS ID: {$ewsNotification->getId()}", $logContext);
}
} else {
$this->logger->error("No tweet response for EWS ID: {$ewsNotification->getId()}");
}
} catch (\Throwable $e) {
$this->logger->error("Exception occurred while posting to Twitter for EWS ID: {$ewsNotification->getId()} - " . $e->getMessage(), [
'exception' => $e->getTraceAsString()
]);
}
}
}
}