2025-11-21 04:04:39 +00:00
< ? php
namespace console\controllers ;
use console\models\ApiToken ;
use console\models\HanumanResultSikarinCheck ;
use console\models\LisResult ;
use yii\console\Controller ;
use Yii ;
class LisSendController extends Controller
{
/**
* Console action : รันกระบวนการส่งผลไปยัง external API
* เรียกจาก CLI : php / path / to / yii lis - api - send / create
*/
public function actionCreate ()
{
error_log ( " === Hanuman Result Sikarin START === " );
$query = HanumanResultSikarinCheck :: find ()
-> where ([ 'not' , [ 'RiaHDocID' => null ]])
-> andWhere ([ 'not' , [ 'PatHN' => null ]])
-> andWhere ([ '<>' , 'RiaHDocID' , '' ])
-> andWhere ([ '<>' , 'PatHN' , '' ])
-> asArray ()
-> orderBy ([ 'RiaHDocDate' => SORT_DESC ])
2025-11-25 10:17:28 +00:00
-> one ();
2025-11-21 04:04:39 +00:00
error_log ( " Total records: " . count ( $query ));
$sendMapping = [];
// config
$cfg = Yii :: $app -> params [ 'external_api' ] ? ? null ;
if ( ! $cfg || empty ( $cfg [ 'receiveUrl' ])) {
2025-11-25 10:17:28 +00:00
error_log ( " Missing external_api config or receiveUrl " );
2025-11-21 04:04:39 +00:00
return 1 ;
}
// get token
$tokenError = null ;
$token = $this -> getValidApiToken ( $cfg , $tokenError );
if ( empty ( $token )) {
2025-11-25 10:17:28 +00:00
error_log ( " Cannot obtain valid API token: " .
( is_array ( $tokenError ) ? json_encode ( $tokenError ) : ( $tokenError ? ? 'unknown' )));
2025-11-21 04:04:39 +00:00
return 1 ;
}
$url = $cfg [ 'receiveUrl' ];
error_log ( " Using API token (ready to send) " );
2025-11-25 10:17:28 +00:00
// ---------- build grouped payloads ----------
2025-11-21 04:04:39 +00:00
$groupedByLabNo = [];
2025-11-25 10:17:28 +00:00
$groupedRows = []; // เก็บแถวต้นฉบับต่อ labNo เพื่อใช้บันทึก LisResult ทีหลัง
2025-11-21 04:04:39 +00:00
2025-11-25 10:17:28 +00:00
$query_lab = HanumanResultSikarinCheck :: find ()
-> where ([ 'not' , [ 'RiaHDocID' => null ]])
-> andWhere ([ 'not' , [ 'PatHN' => null ]])
-> andWhere ([ '<>' , 'RiaHDocID' , '' ])
-> andWhere ([ '<>' , 'PatHN' , '' ])
-> andWhere ([ 'LabNo' => $query [ 'LabNo' ]])
-> asArray ()
-> orderBy ([ 'RiaHDocDate' => SORT_DESC ])
-> all ();
foreach ( $query_lab as $rows ) {
2025-11-21 04:04:39 +00:00
$filesData = [];
$timestamp = date ( 'dmYHis' );
$labNo = $rows [ 'LabNo' ] ? ? '' ;
$docIdParam = $rows [ 'RiaHDocID' ] ? ? '' ;
$docDate = ! empty ( $rows [ 'RiaHDocDate' ]) ? date ( 'Y-m-d' , strtotime ( $rows [ 'RiaHDocDate' ])) : '' ;
if ( ! empty ( $docIdParam )) {
$LisResultUrl = " https://report.prolab.co.th/prolab/printpdf.php?docID= { $docIdParam } &docDate= { $docDate } " ;
$pdfContent = $this -> fetchUrl ( $LisResultUrl , 20 );
if ( $pdfContent !== false && strlen ( $pdfContent ) > 0 ) {
$filesData [] = [
'FileName' => " { $labNo } _ { $timestamp } .pdf " ,
'Filebase64' => base64_encode ( $pdfContent ),
];
}
$localDir = " /var/www/html/pdflink/ { $docIdParam } " ;
if ( is_dir ( $localDir )) {
foreach ( scandir ( $localDir ) as $fn ) {
if ( $fn === '.' || $fn === '..' ) continue ;
if ( ! preg_match ( '/\.(pdf|jpg|jpeg|png|doc|docx)$/i' , $fn )) continue ;
$path = " { $localDir } / { $fn } " ;
if ( is_file ( $path ) && is_readable ( $path )) {
$content = @ file_get_contents ( $path );
if ( $content !== false ) {
$filesData [] = [
'FileName' => " { $labNo } _ { $timestamp } _ { $fn } " ,
'Filebase64' => base64_encode ( $content ),
];
}
}
}
}
}
2025-11-25 10:17:28 +00:00
// build test item
2025-11-21 04:04:39 +00:00
$testItem = [
'TestCode' => ( string )( $rows [ 'TestCode' ] ? ? '' ),
'TestName' => ( string )( $rows [ 'TestName' ] ? ? '' ),
'TestRemark' => $rows [ 'TestRemark' ] ? ? '' ,
'InformCriticalByCode' => '' ,
'InformCriticalBy' => '' ,
'InformCriticalTo' => '' ,
'InformCriticalDateTime' => '' ,
'CriticalFlag' => '' ,
'ReportResultByCode' => '' ,
'ReportResultBy' => ( string )( $rows [ 'RiaLDUserNameEntry' ] ? ? '' ),
'ReportResultDateTime' => $this -> dateTimeFormat ( $rows [ 'RiaLDUserDateEntry' ] ? ? '' ),
'ApproveResultByCode' => '' ,
'ApproveResultBy' => ( string )( $rows [ 'RiaLDUserNameAppr' ] ? ? '' ),
'ApproveResultDateTime' => $this -> dateTimeFormat ( $rows [ 'RiaLDUserDateAppr' ] ? ? '' ),
'Filedata' => $filesData ,
'ResultList' => [[
'ResultCode' => ( string )( $rows [ 'ResultCode' ] ? ? '' ),
'ResultName' => ( string )( $rows [ 'ResultName' ] ? ? '' ),
'ResultValue' => ( string )( $rows [ 'RiaLDRsltAnal' ] ? ? '' ),
'ResultUnit' => ( string )( $rows [ 'LabUnit' ] ? ? '' ),
'ResultFlag' => '' ,
'ReferenceRange' => trim (( $rows [ 'LabNormal1' ] ? ? '' ) . ' ' . ( $rows [ 'LabNormal2' ] ? ? '' )),
'ResultRemark' => '' ,
]],
];
if ( ! isset ( $groupedByLabNo [ $labNo ])) {
$groupedByLabNo [ $labNo ] = [
'LabNo' => $labNo ,
'RequestRemark' => '' ,
'ResultStatus' => '' ,
'TestList' => [],
];
}
$groupedByLabNo [ $labNo ][ 'TestList' ][] = $testItem ;
2025-11-25 10:17:28 +00:00
$groupedRows [ $labNo ][] = $rows ; // เก็บแถวต้นฉบับต่อ lab
2025-11-21 04:04:39 +00:00
$sendMapping [ $rows [ 'RiaHDocID' ]] = $rows [ 'RiaHDocID' ];
2025-11-25 10:17:28 +00:00
} // end foreach build
2025-11-21 04:04:39 +00:00
2025-11-25 10:17:28 +00:00
// ---------- ส่งแต่ละ payload ที่ grouped ----------
foreach ( $groupedByLabNo as $labNo => $payload ) {
2025-11-21 04:04:39 +00:00
if ( empty ( $payload ) || ! isset ( $payload [ 'LabNo' ])) {
2025-11-25 10:17:28 +00:00
$labKey = $payload [ 'LabNo' ] ? ? ( $labNo ? ? '(unknown)' );
error_log ( " Skipping send: payload missing LabNo for key= { $labKey } " );
2025-11-21 04:04:39 +00:00
continue ;
}
$payloadJson = json_encode ( $payload , JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES );
2025-11-25 10:17:28 +00:00
$payloadJson = ( $payloadJson === false ) ? var_export ( $payload , true ) : $payloadJson ;
2025-11-21 04:04:39 +00:00
error_log ( " Payload (truncated): " . $this -> truncateForLog ( $payloadJson , 8192 ));
$tests = array_map ( function ( $t ) {
2025-11-25 10:17:28 +00:00
$code = $t [ 'TestCode' ] ? ? '(noCode)' ;
$name = $t [ 'TestName' ] ? ? '(noName)' ;
2025-11-21 04:04:39 +00:00
return $code . ':' . $name ;
}, $payload [ 'TestList' ] ? ? []);
2025-11-25 10:17:28 +00:00
error_log ( " Sending payload for LabNo= { $labNo } (tests= " . json_encode ( $tests , JSON_UNESCAPED_UNICODE ) . " ) " );
2025-11-21 04:04:39 +00:00
$response = $this -> postJsonCurl ( $url , $payload , [
'Authorization' => " Bearer { $token } " ,
'Content-Type' => 'application/json' ,
]);
$lastResponse = $response ;
$rawResp = $response [ 'response' ] ? ? '' ;
2025-11-25 10:17:28 +00:00
$httpCode = ( int )( $response [ 'http_code' ] ? ? 0 );
2025-11-21 04:04:39 +00:00
$curlErr = $response [ 'curl_error' ] ? ? null ;
if ( ! empty ( $curlErr )) {
2025-11-25 10:17:28 +00:00
error_log ( " WARNING: cURL error: { $curlErr } " );
2025-11-21 04:04:39 +00:00
}
2025-11-25 10:17:28 +00:00
if ( $httpCode === 401 ) {
error_log ( " 401 Unauthorized received — refreshing token and retrying " );
2025-11-21 04:04:39 +00:00
$token = $this -> getValidApiToken ( $cfg , $tokenError );
if ( ! empty ( $token )) {
error_log ( " Retrying with refreshed token. Payload (truncated): " . $this -> truncateForLog ( $payloadJson , 8192 ));
$response = $this -> postJsonCurl ( $url , $payload , [
'Authorization' => " Bearer { $token } " ,
'Content-Type' => 'application/json' ,
]);
$lastResponse = $response ;
$rawResp = $response [ 'response' ] ? ? '' ;
2025-11-25 10:17:28 +00:00
$httpCode = ( int )( $response [ 'http_code' ] ? ? 0 );
2025-11-21 04:04:39 +00:00
$curlErr = $response [ 'curl_error' ] ? ? null ;
if ( ! empty ( $curlErr )) {
2025-11-25 10:17:28 +00:00
error_log ( " WARNING: cURL error on retry: { $curlErr } " );
2025-11-21 04:04:39 +00:00
}
} else {
2025-11-25 10:17:28 +00:00
error_log ( " ERROR: Failed to refresh token after 401 " );
2025-11-21 04:04:39 +00:00
}
}
2025-11-25 10:17:28 +00:00
error_log ( " Response (http= { $httpCode } ): " . $this -> truncateForLog (( string ) $rawResp , 8192 ));
2025-11-21 04:04:39 +00:00
// decode and check success
$decoded = json_decode ( $rawResp , true );
$statusVal = $decoded [ 'Status' ] ? ? $decoded [ 'status' ] ? ? null ;
$messageVal = $decoded [ 'Message' ] ? ? $decoded [ 'message' ] ? ? '' ;
$success = false ;
if ( is_numeric ( $statusVal )) {
$success = ( intval ( $statusVal ) === 0 );
} elseif ( is_string ( $statusVal ) && strtolower ( $statusVal ) === 'success' ) {
$success = true ;
} elseif ( is_string ( $messageVal ) && strpos ( strtolower ( $messageVal ), 'success' ) !== false ) {
$success = true ;
} elseif ( is_string ( $rawResp ) && strpos ( strtolower ( $rawResp ), '"status":0' ) !== false ) {
$success = true ;
}
if ( $success ) {
2025-11-25 10:17:28 +00:00
error_log ( " Success LabNo= { $labNo } " );
// บันทึก LisResult สำหรับทุก TestList ใน lab นี้
$testList = $payload [ 'TestList' ] ? ? [];
foreach ( $testList as $testItem ) {
$testCode = ( string )( $testItem [ 'TestCode' ] ? ? '' );
$testName = ( string )( $testItem [ 'TestName' ] ? ? '' );
$resultValue = $testItem [ 'ResultList' ][ 0 ][ 'ResultValue' ] ? ? '' ;
$resultUnit = $testItem [ 'ResultList' ][ 0 ][ 'ResultUnit' ] ? ? '' ;
$referenceRange = $testItem [ 'ResultList' ][ 0 ][ 'ReferenceRange' ] ? ? '' ;
// หาแถวต้นฉบับที่ตรงกับ testCode เพื่อดึง CustID/HN/RiaHDocID ถ้ามี
$matchRow = null ;
if ( ! empty ( $groupedRows [ $labNo ])) {
foreach ( $groupedRows [ $labNo ] as $r ) {
if (( string )( $r [ 'TestCode' ] ? ? '' ) === $testCode ) {
$matchRow = $r ;
break ;
}
}
}
// ถ้าไม่พบ ให้ใช้แถวแรกเป็น fallback (ถ้ามี)
if ( $matchRow === null && ! empty ( $groupedRows [ $labNo ])) {
$matchRow = $groupedRows [ $labNo ][ 0 ];
}
$custId = $matchRow [ 'CustID' ] ? ? null ;
$hn = $matchRow [ 'PatHN' ] ? ? null ;
$riahDocId = $matchRow [ 'RiaHDocID' ] ? ? null ;
$riahDocDate = $matchRow [ 'RiaHDocDate' ] ? ? null ;
// ตรวจสอบว่ามีอยู่แล้วหรือยัง (ใช้ lab_no + test_code + cust_id + hn)
$existsQuery = [
'lab_no' => $labNo ,
'test_code' => $testCode ,
];
if ( $custId !== null ) $existsQuery [ 'cust_id' ] = $custId ;
if ( $hn !== null ) $existsQuery [ 'hn' ] = $hn ;
$exists = LisResult :: find () -> where ( $existsQuery ) -> exists ();
if ( ! $exists ) {
$LisResult = new LisResult ([
'lab_no' => $labNo ,
'riah_doc_id' => $riahDocId ,
'riah_doc_date' => $riahDocDate ,
'test_code' => $testCode ,
'test_name' => $testName ,
'cust_id' => $custId ,
'hn' => $hn ,
'result_value' => $resultValue ? ? '' ,
'result_unit' => $resultUnit ? ? '' ,
'reference_range' => trim (( string ) $referenceRange ),
'status' => 1 ,
]);
$LisResult -> save ( false );
} else {
trigger_error ( " Record already exists in LisResult, skipping insert: LabNo= { $labNo } , TestCode= { $testCode } , CustID= { $custId } , HN= { $hn } " , E_USER_WARNING );
}
} // end foreach testList
2025-11-21 04:04:39 +00:00
} else {
$msg = $lastResponse [ 'response' ] ? ? ( $lastResponse [ 'curl_error' ] ? ? 'ไม่พบข้อมูลตอบกลับ' );
error_log ( " FAIL LabNo= { $labNo } ; last_http= " . ( $lastResponse [ 'http_code' ] ? ? 'ไม่พบข้อมูลตอบกลับ' ) . " ; message= " . $this -> truncateForLog ( $msg , 1024 ));
}
2025-11-25 10:17:28 +00:00
// optional small delay: usleep(200000);
} // end foreach groupedByLabNo
2025-11-21 04:04:39 +00:00
error_log ( " === Hanuman Result Sikarin END === " );
return 0 ;
}
2025-11-25 10:17:28 +00:00
2025-11-21 04:04:39 +00:00
/** helper: ส่ง JSON ผ่าน cURL (คืนข้อมูล debug เต็ม) */
protected function postJsonCurl ( $url , $payload , $headers = [])
{
$ch = curl_init ( $url );
$jsonPayload = json_encode ( $payload , JSON_UNESCAPED_UNICODE );
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
curl_setopt ( $ch , CURLOPT_POST , true );
curl_setopt ( $ch , CURLOPT_POSTFIELDS , $jsonPayload );
// security: allow config to control SSL verify
$verifySsl = Yii :: $app -> params [ 'external_api' ][ 'verify_ssl' ] ? ? true ;
curl_setopt ( $ch , CURLOPT_SSL_VERIFYPEER , $verifySsl );
curl_setopt ( $ch , CURLOPT_SSL_VERIFYHOST , $verifySsl ? 2 : 0 );
curl_setopt ( $ch , CURLOPT_TIMEOUT , 60 );
curl_setopt ( $ch , CURLOPT_CONNECTTIMEOUT , 10 );
curl_setopt ( $ch , CURLOPT_FOLLOWLOCATION , true );
$curlHeaders = [ 'Content-Type: application/json' , 'Accept: application/json' , 'Expect:' , 'User-Agent: MyLabSender/1.0' ];
foreach ( $headers as $k => $v ) {
if ( is_int ( $k )) {
$curlHeaders [] = $v ;
} else {
$curlHeaders [] = " { $k } : { $v } " ;
}
}
curl_setopt ( $ch , CURLOPT_HTTPHEADER , $curlHeaders );
$response = curl_exec ( $ch );
$httpCode = curl_getinfo ( $ch , CURLINFO_HTTP_CODE );
$curlErrno = curl_errno ( $ch );
$curlError = $curlErrno ? curl_error ( $ch ) : null ;
curl_close ( $ch );
return [
'http_code' => $httpCode ,
'response' => $response ,
'curl_error' => $curlError ,
'curl_errno' => $curlErrno ,
'url' => $url ,
'payload_size' => strlen ( $jsonPayload ),
];
}
/**
* helper : fetch URL via cURL ( robust )
*/
protected function fetchUrl ( $url , $timeout = 10 )
{
$ch = curl_init ( $url );
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
curl_setopt ( $ch , CURLOPT_FOLLOWLOCATION , true );
curl_setopt ( $ch , CURLOPT_TIMEOUT , $timeout );
curl_setopt ( $ch , CURLOPT_CONNECTTIMEOUT , 5 );
curl_setopt ( $ch , CURLOPT_SSL_VERIFYPEER , false );
curl_setopt ( $ch , CURLOPT_SSL_VERIFYHOST , false );
$data = curl_exec ( $ch );
$http = curl_getinfo ( $ch , CURLINFO_HTTP_CODE );
$err = curl_errno ( $ch ) ? curl_error ( $ch ) : null ;
curl_close ( $ch );
if ( $data === false || $http >= 400 ) {
//$this->logConsole("fetchUrl failed: {$url} http={$http} err=" . ($err ?? 'none'), 'warning');
error_log ( " fetchUrl failed: { $url } http= { $http } err= " . ( $err ? ? 'none' ), 'warning' );
return false ;
}
return $data ;
}
/**
* Log helper — writes to STDOUT with timestamp and also to Yii log .
* $level : 'info' | 'warning' | 'error'
*/
protected function logConsole ( $message , $level = 'info' )
{
$time = date ( 'Y-m-d H:i:s' );
$line = " [ { $time } ] { $message } " . PHP_EOL ;
// write to console
$this -> stdout ( $line );
// write to Yii logger with appropriate level
switch ( strtolower ( $level )) {
case 'error' :
Yii :: error ( $message , __METHOD__ );
break ;
case 'warning' :
Yii :: warning ( $message , __METHOD__ );
break ;
default :
Yii :: info ( $message , __METHOD__ );
}
}
/**
* Truncate long strings for logging . $maxBytes = null => no truncation .
*/
protected function truncateForLog ( $text , $maxBytes = 4096 )
{
if ( $text === null ) return '' ;
if ( $maxBytes === null ) return $text ;
$len = strlen ( $text );
if ( $len <= $maxBytes ) return $text ;
$prefix = substr ( $text , 0 , $maxBytes );
return $prefix . " \n ...TRUNCATED... (original_length= { $len } ) " ;
}
/** helper: แปลง datetime เป็น dd/mm/YYYY H:i:s */
public function dateTimeFormat ( $value )
{
if ( empty ( $value )) return '' ;
try {
$dt = new \DateTime ( $value );
return $dt -> format ( 'd/m/Y H:i:s' );
} catch ( \Throwable $e ) {
return '' ;
}
}
/**
* ขอ token จาก API ( คืนค่า associative array แบบ { ok , token , expires_at , http_code , raw , error })
*/
protected function getApiToken ( $cfg )
{
$tokenUrl = $cfg [ 'tokenUrl' ] ? ? Yii :: $app -> params [ 'external_api' ][ 'tokenUrl' ] ? ? null ;
$username = $cfg [ 'username' ] ? ? Yii :: $app -> params [ 'external_api' ][ 'username' ] ? ? null ;
$password = $cfg [ 'password' ] ? ? Yii :: $app -> params [ 'external_api' ][ 'password' ] ? ? null ;
$payload = [ 'username' => $username , 'password' => $password ];
$ch = curl_init ( $tokenUrl );
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , true );
curl_setopt ( $ch , CURLOPT_POST , true );
curl_setopt ( $ch , CURLOPT_POSTFIELDS , json_encode ( $payload ));
curl_setopt ( $ch , CURLOPT_HTTPHEADER , [ 'Content-Type: application/json' , 'Accept: application/json' ]);
curl_setopt ( $ch , CURLOPT_TIMEOUT , 15 );
curl_setopt ( $ch , CURLOPT_CONNECTTIMEOUT , 5 );
curl_setopt ( $ch , CURLOPT_SSL_VERIFYPEER , false );
curl_setopt ( $ch , CURLOPT_SSL_VERIFYHOST , false );
$raw = curl_exec ( $ch );
$httpCode = curl_getinfo ( $ch , CURLINFO_HTTP_CODE );
$curlErr = curl_errno ( $ch ) ? curl_error ( $ch ) : null ;
curl_close ( $ch );
$result = [ 'ok' => false , 'token' => null , 'expires_at' => null , 'http_code' => $httpCode , 'raw' => $raw , 'error' => null ];
if ( $raw === false || $curlErr ) {
$result [ 'error' ] = 'cURL error: ' . ( $curlErr ? ? 'unknown' );
return $result ;
}
$decoded = json_decode ( $raw , true );
if ( json_last_error () !== JSON_ERROR_NONE ) {
$result [ 'error' ] = 'Invalid JSON response from token endpoint' ;
return $result ;
}
if ( ! empty ( $decoded [ 'access_token' ])) {
$result [ 'ok' ] = true ;
$result [ 'token' ] = $decoded [ 'access_token' ];
$expiresIn = intval ( $decoded [ 'expires_in' ] ? ? 3600 );
$result [ 'expires_at' ] = date ( 'Y-m-d H:i:s' , time () + $expiresIn );
} elseif ( ! empty ( $decoded [ 'token' ])) {
$result [ 'ok' ] = true ;
$result [ 'token' ] = $decoded [ 'token' ];
$expiresIn = intval ( $decoded [ 'expires_in' ] ? ? 3600 );
$result [ 'expires_at' ] = date ( 'Y-m-d H:i:s' , time () + $expiresIn );
} else {
$result [ 'error' ] = $decoded [ 'error' ] ? ? ( $decoded [ 'message' ] ? ? 'No token in response' );
}
return $result ;
}
/**
* ดึง token ที่ valid ( คืน token string หรือ null และตั้ง $tokenError หากมีปัญหา )
* พร้อม debug log วันที่หมดอายุของ Token
*/
protected function getValidApiToken ( $cfg , & $tokenError = null )
{
$apiName = $cfg [ 'apiName' ] ? ? 'gems_api' ;
$tokenModel = ApiToken :: find () -> where ([ 'api_name' => $apiName ]) -> one ();
$token = null ;
$nowTs = time ();
$refreshMargin = $cfg [ 'refreshMargin' ] ? ? 300 ; // 5 นาที
$needRequest = ! $tokenModel || ( strtotime ( $tokenModel -> expires_at ) <= ( $nowTs + $refreshMargin ));
if ( $tokenModel ) {
//$this->logConsole("Token in DB found for {$apiName}: expires_at={$tokenModel->expires_at}, token_prefix=" . substr($tokenModel->token ?? '', 0, 15) . "...");
error_log ( " Token in DB found for { $apiName } : expires_at= { $tokenModel -> expires_at } , token_prefix= " . substr ( $tokenModel -> token ? ? '' , 0 , 15 ) . " ... " );
} else {
error_log ( " No token found in DB for { $apiName } , will request new token " );
//$this->logConsole("No token found in DB for {$apiName}, will request new token");
}
if ( $needRequest ) {
$tokenResp = $this -> getApiToken ( $cfg );
if ( empty ( $tokenResp ) || empty ( $tokenResp [ 'ok' ])) {
$tokenError = [
'message' => 'Failed to get token from API' ,
'tokenUrl' => $cfg [ 'tokenUrl' ] ? ? null ,
'error' => $tokenResp [ 'error' ] ? ? 'Unknown error' ,
'http_code' => $tokenResp [ 'http_code' ] ? ? 0 ,
'raw' => $tokenResp [ 'raw' ] ? ? null ,
];
if ( $tokenModel && ! empty ( $tokenModel -> token )) {
error_log ( " Using old token as fallback (expires_at= { $tokenModel -> expires_at } ) " );
//$this->logConsole("Using old token as fallback (expires_at={$tokenModel->expires_at})");
return $tokenModel -> token ; // fallback
}
return null ;
}
$token = $tokenResp [ 'token' ];
$expiresAt = $tokenResp [ 'expires_at' ] ? ? date ( 'Y-m-d H:i:s' , time () + 3600 );
if ( ! $tokenModel ) {
$tokenModel = new ApiToken ();
$tokenModel -> api_name = $apiName ;
}
$tokenModel -> token = $token ;
$tokenModel -> expires_at = $expiresAt ;
try {
$tokenModel -> save ( false );
error_log ( " New token saved: api_name= { $apiName } , expires_at= { $expiresAt } , token_prefix= " . substr ( $token ? ? '' , 0 , 15 ) . " ... " );
//$this->logConsole("New token saved: api_name={$apiName}, expires_at={$expiresAt}, token_prefix=" . substr($token, 0, 15) . "...");
} catch ( \Throwable $e ) {
//$this->logConsole("Error saving new token: " . $e->getMessage(), 'error');
error_log ( " Error saving new token: " . $e -> getMessage (), 'error' );
if ( $tokenModel && ! empty ( $tokenModel -> token )) {
return $tokenModel -> token ; // fallback
}
$tokenError = $e -> getMessage ();
return null ;
}
} else {
$token = $tokenModel -> token ;
//$this->logConsole("Reusing valid token: expires_at={$tokenModel->expires_at}, token_prefix=" . substr($token, 0, 15) . "...");
error_log ( " Reusing valid token: expires_at= { $tokenModel -> expires_at } , token_prefix= " . substr ( $token , 0 , 15 ) . " ... " );
}
return $token ;
}
}