Files
ExpenseCount/app/Controller/Component/NotificationComponent.php
2026-06-25 13:03:45 +06:00

163 lines
5.7 KiB
PHP

<?php
App::uses('Component', 'Controller');
App::uses('CakeEmail', 'Network/Email');
require_once(APP . 'Controller' . DS . 'Traits' . DS . 'ApiCallTrait.php');
use Google\Auth\Credentials\ServiceAccountCredentials;
class NotificationComponent extends Component
{
use ApiCallTrait;
/**
* @var AppModel|bool|mixed|Model|object|string|null
*/
private $PushToken;
public function initialize(Controller $controller)
{
$this->PushToken = ClassRegistry::init('PushToken');
}
public function sendEmail($data) {
$default = array(
'host' => Configure::read('expensecount.email.smtp.host'),
'port' => 587,
'auth' => 'plain',
'username' => Configure::read('expensecount.email.smtp.username'),
'password' => Configure::read('expensecount.email.smtp.password'),
'tsl' => false,
'transport' => 'Smtp',
'from' => array(Configure::read('expensecount.email.smtp.from') => 'ExpenseCount'),
'returnPath' => Configure::read('expensecount.email.smtp.from'),
'layout' => false,
'emailFormat' => 'html',
'charset' => 'utf-8',
'headerCharset' => 'utf-8',
);
try {
$Email = new CakeEmail($default);
$Email->to($data["email_to"]);
$Email->emailFormat('html');
$Email->template($data["template"], null)->viewVars(array('data' => $data));
$Email->subject($data["subject"]);
$Email->replyTo($data["email_from"]);
$Email->from(array(Configure::read('expensecount.email.smtp.from') => "ExpenseCount.com"));
$Email->delivery = 'Smtp';
return $Email->send();
}catch (Exception $e) {
CakeLog::write(LOG_ERR, 'Email sending failed: ' . $e->getMessage());
return $e->getMessage();
}
}
private function getAccessToken()
{
$cacheFile = TMP . 'fcm_token.cache';
if (file_exists($cacheFile)) {
$cached = json_decode(file_get_contents($cacheFile), true);
if (!empty($cached['token']) && $cached['expires_at'] > time()) {
return $cached['token'];
}
}
$scopes = ['https://www.googleapis.com/auth/firebase.messaging'];
$credentials = new ServiceAccountCredentials(
$scopes,
json_decode(file_get_contents(FIREBASE_SECRET), true)
);
$token = $credentials->fetchAuthToken();
if (!isset($token['access_token'])) {
throw new \Exception('Unable to get access token');
}
// Google tokens expire in 3600s; cache for 55 minutes to stay safely within that.
file_put_contents($cacheFile, json_encode([
'token' => $token['access_token'],
'expires_at' => time() + 3300,
]));
return $token['access_token'];
}
public function sendPushNotification($tokens, $message, $async = false)
{
$projectId = FIREBASE_PROJECT_ID;
if (empty($projectId)) {
CakeLog::write(LOG_ERR, 'Push notification: Firebase project_id not configured');
return ['error' => 'Firebase project_id not configured'];
}
$url = "https://fcm.googleapis.com/v1/projects/{$projectId}/messages:send";
try {
$accessToken = $this->getAccessToken();
} catch (\Exception $e) {
CakeLog::write(LOG_ERR, 'Push notification: Failed to get access token: ' . $e->getMessage());
return ['error' => 'Failed to get access token: ' . $e->getMessage()];
}
$responses = [];
foreach ($tokens as $key => $token) {
$payload = [
"message" => [
"token" => $token['token'],
"data" => $message,
"apns" => [
"payload" => [
"aps" => [
"alert" => [
"title" => $message['title'],
"body" => $message['body']
],
"sound" => "default",
"badge" => 1,
"mutable-content" => 1,
"content-available" => 1
]
]
]
]
];
$apiResponse = $this->fireAndForget($url, $payload, $accessToken);
$responses[] = ['request' => [$token['user_id'], $token['device_id']], 'response' => $apiResponse];
}
return $responses;
}
public function send($users,$message){
$tokens = array();
if(!empty($users)){
$filter = array('status' => 1,'user_id' => $users);
$db_token = $this->PushToken->getToken($filter);
if(!empty($db_token)) {
foreach ($db_token as $token) {
$tokens[] = ['user_id'=>$token['PushToken']['user_id'],
'device_id'=>$token['PushToken']['device_id'],
'token'=> $token['PushToken']['push_token']];
}
}
if(!empty($tokens)) {
$response = $this->sendPushNotification($tokens, $message, true);
}else{
$response["status"] = "-99";
$response["status_desc"] = "Push Token Not Found!";
$response["input"] = $users;
}
}else{
$response["status"] = "-99";
$response["status_desc"] = "User Not Found!";
$response["input"] = $users;
}
return $response;
}
}