getMessage() . $eos; static::$errors[] = $t->getMessage(); } static::$class = __CLASS__; static::$debug = (isset(gasConfig::$settings[STRING_DEBUG])) ? gasConfig::$settings[STRING_DEBUG] : false; } /** * singleton() -- public static class * * method to instantiate the resourceManager singleton class * * note: * ----- * it's the calling client's responsibility to check for the null return value in the member variable $instance. * * @author mike@givingassistant.org * @version 1.0 * * @return null * * HISTORY: * ======== * 06-09-17 mks original coding * */ public static function singleton() { if (static::$instance === null) { $c = __CLASS__; static::$instance = new $c(); } return(static::$instance); } /** * getInstance() -- public static method * * this is the singleton constructor entry point for the class. returns a resource pointer to the static or * a null value if the instantiation failed. * * USAGE: * ------ * $resourcePointer = pgsStatic::getInstance(); * * @author mike@givingassistant.org * @version 1.0 * * @return mixed * * HISTORY: * ======== * 06-09-17 mks original coding * */ public static function getInstance() { if (static::$instance === null) { $c = __CLASS__; static::$instance = new $c(); } return (static::$instance); } /** * doingTime() -- public static method * * public static method that creates a timer (micro-time) value. * * _start is the input parameter (defaults to Boolean(false)) -- if this value is false, then the method will * immediately return a generated timer value to the client. * * if _start is provided, then get a second timer value and derive the difference between the current and the * start-time returning the total time calculated. * * USAGE: * ------ * pgsStatic::getInstance()->doingTime($startValue); * * @author mike@givingassistant.org * @version 1.0 * * @param integer $_start * @return float|int * * HISTORY: * ======== * 06-09-17 mks original coding * */ public static function doingTime(int $_start = 0) { if ($_start == 0) { return (time() + microtime(true)); } $end = time() + microtime(true); return (round(floatval($end - floatval($_start)), NUMBER_FP_PRECISION)); } /** * publishSystemEvent() -- public method * * This method is invoked when we want to publish a system event to the (remote) admin service. The method requires * a single input parameter: the data ball in array format which represents one, or more, broker event records. * * The method is responsible for ensuring the data ball is in the correct format (an array of records), and for * building the payload that's published to the admin service. * * The method returns a false on processing error, or if the packet fails to send. A true return means that the * payload was successfully submitted to the (remote) service. It does not indicate that the record was * successfully processed and inserted into the collection as that part of the process is black-boxed behind RMQ. * * @author mike@givingassistant.org * @version 1.0 * * @param array $_data the record to be published remotely * @param array $_meta the meta data for the sysEvent record to be published * @param string $_og the original event guid * @param array|null $_es call-by-reference parameter to contain the error stack * @return bool * * HISTORY: * ======== * 08-17-17 mks CORE-500: original coding * 08-13-20 mks DB-168: method renamed, meta added to params, refactored, and moved to gasStatic class * */ public static function publishSystemEvent(array $_data, array $_meta, string $_og = '', ?array $_es = null): bool { $bc = null; // validate that the $_data payload is not empty if (empty($_data)) { $msg = ERROR_DATA_ARRAY_EMPTY . COLON . STRING_DATA; $_es[] = $msg; return false; } if (empty($_meta)) { $msg = ERROR_DATA_ARRAY_EMPTY . COLON . STRING_META; $_es[] = $msg; return false; } // validate that we're getting an array of records ($_data[0] = record1, etc.) if (key($_data) !== 0) { $msg = ERROR_DATA_ARRAY_NOT_ARRAY . STRING_DATA; $_es[] = $msg; return false; } try { // instantiate an AI broker client $bc = static::fetchAIClient($_es); if (is_null($bc)) return false; if (!empty($_og) and validateGUID($_og)) $_meta[META_EVENT_GUID] = $_og; $request = [ BROKER_REQUEST => BROKER_REQUEST_ADMIN_BROKER_EVENT, BROKER_DATA => $_data, BROKER_META_DATA => $_meta ]; $response = $bc->call(gzcompress(json_encode($request))); // rpc queue if (is_object($bc)) $bc->__destruct(); unset($bc); return ($response); } catch (Throwable $t) { $hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__); @handleExceptionMessaging($hdr, $t->getMessage(), $_es); if (is_object($bc)) $bc->__destruct(); unset($bc); return false; } } /** * fetchAIClient() -- private method * * This method instantiates a new AdminIN broker client and assigns the object to the $aiClient property. * * The method checks to see if there's already an object attached before instantiating a new one. * * The method returns a BOOL value that indicates if the instantiation was successful or not. * * * @param array|null $_es -- call-by-reference parameter containing the method's error stack output * @return null|gacWorkQueueClient * * HISTORY: * ======== * 08-17-17 mks CORE-500: original coding * 09-10-20 mks DB-168: improved error handling, moved to static class, changed return type to obj * *@author mike@givingassistant.org * @version 1.0 * */ private static function fetchAIClient(?array &$_es):?gacWorkQueueClient { $bc = null; $foo = null; $method = basename(__METHOD__); try { $bc = new gacWorkQueueClient($method . AT . __LINE__); if (!$bc->status) { $hdr = sprintf(INFO_LOC, $method, __LINE__); $msg = ERROR_FAILED_TO_INSTANTIATE . RESOURCE_ADMIN_CLIENT; $_es[] = $msg; static::$logger->error($hdr . $msg); if (is_object($bc)) $bc->__destruct(); unset($bc); return null; } return $bc; } catch (Throwable | TypeError $t) { $hdr = sprintf(INFO_LOC, $method, __LINE__); $_es[] = ERROR_THROWABLE_EXCEPTION; @handleExceptionMessaging($hdr, $t->getMessage(), $foo, true); if (is_object($bc)) $bc->__destruct(); unset($bc); return null; } } /** * createATJob() -- public static method * * this is a private method providing a single point-of-access to the create-AT-Job function. the method requires * the following input parameters: * * -- duration (in seconds) from "now" when the session will expire * -- the systemEvent token that will be passed to the PHP script, invoked by AT(1) * -- $_script - should be one of two values: used the session script for backward compatibility * * since this is an internal method, there's no error checking or parameter validation - this method will only * execute if the admin service is local to the current instance. * * the function returns the AT output back to the calling client as a string or a null if the admin service is not * local to the current instance or if an exception was raised during processing. * * * @author mike@givingassistant.org * @version 1.0 * * @param int $_duration * @param string $_sysEvToken * @param string $_script * @return null | string * * HISTORY: * ======== * 08-13-20 mks DB-168: original coding * */ public static function createATJob(int $_duration, string $_sysEvToken, string $_script = FILE_EOS):?string { if (gasConfig::$settings[ENV_ADMIN][CONFIG_IS_LOCAL]) { $time = 'now + ' . floor($_duration / NUMBER_SECS_IN_MIN) . ' ' . STRING_SYS_MIN; $job = '/usr/bin/php -f ' . dirname(__DIR__) . DIR_SCRIPTS . $_script . ' ' . $_sysEvToken; return (gacATWrapper::cmd($job, $time)); } else { try { $hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__); $msg = ERROR_REMOTE_NOT_ADMIN; static::$logger->warn($hdr . $msg); consoleLog(static::$res, CON_ERROR, $msg); } catch (TypeError | Throwable $t) { $hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__); static::$logger->warn($hdr . $t->getMessage()); consoleLog(static::$res, CON_ERROR, $t->getMessage()); } return null; } } /** * convertWebMigrationRequest() -- public static method * * This function is called from the migration broker when we receive a migration request from the webUI. * * There is one input parameter for this method: * * $_data -- the array passed from the broker which contains the event payload data * * The method returns an array -- this array will contain a new configuration matrix to temporarily replace * gasConfig::$settings[CONFIG_MIGRATION]. * * The method generates a copy of the migration XML data and then over-writes relevant fields with data received * via the input parameters. * * No validation is performed as the web-app (./utilities/migrateData.php) does all the data validation prior * to publishing the broker event request. * * * @author mike@givingassistant.org * @version 1.0 * * * @param array $_data -- broker event payload data * @return array -- returns a replacement migration configuration (data validated/tested in web-app!) * * * HISTORY: * ======== * 09-27-18 mks DB-43: initial coding * */ public static function convertWebMigrationRequest(array $_data): array { $rd = null; // return data $newMigCfg = gasConfig::$settings[CONFIG_MIGRATION]; // start with a copy of the current config // first, set the schema $schema = $_data[MIGRATION_SOURCE_SCHEMA]; // next, let's replace the common migration XML components that are required in an override-migration request $newMigCfg[$schema][STRING_HOST] = $_data[STRING_HOST]; $newMigCfg[$schema][STRING_PORT] = $_data[STRING_PORT]; $newMigCfg[$schema][CONFIG_DATABASE] = $_data[CONFIG_DATABASE]; // next, if the optional components are set, bring them into the new config array if (isset($_data[STRING_USER])) $newMigCfg[$schema][STRING_USER] = $_data[STRING_USER]; if (isset($_data[STRING_PASS])) $newMigCfg[$schema][STRING_PASS] = $_data[STRING_PASS]; // next, grab the mongo-specific components if ($schema == CONFIG_SCHEMA_MONGO) { $newMigCfg[$schema][STRING_AUTH_SRC] = $_data[STRING_AUTH_SRC]; $newMigCfg[$schema][CONFIG_DATABASE_MONGODB_REPLSET_NAME] = $_data[CONFIG_DATABASE_MONGODB_REPLSET_NAME]; $newMigCfg[$schema][CONFIG_DATABASE_MONGODB_REPLSET_DSN] = $_data[CONFIG_DATABASE_MONGODB_REPLSET_DSN]; } return $newMigCfg; } /** * loadValidTemplateNames() -- private method * * this method loads all of the file names that end with an ".inc" extension that currently reside in the * framework's template directory. * * The file names are loaded into the indexed array and returned to the calling client. * * If we could not open the template directory, then the value for $validTemplates is set to null - which * should be tested by the client on return. * * Additionally, if the template files could not be loaded, we generate both a diagnostics and a logging * error message. * * There are no inputs to this method. The method returns an array of valid template names it sussed from the * template directory, on success, or a null on failure. * * @author mike@givingassistant.com * @version 1.0 * * @return array|null * * HISTORY: * ======== * 06-15-17 mks original coding * 07-07-17 mks fixed error searching for .inc type files * 07-30-18 mks CORE-775: PHP7.2 Exception Handling * 09-13-18 mks DB-43: added option to strip "gat" prepend * 06-11-20 mks ECI-164: can no longer strip the TLTI prefix from template classes * */ public static function loadValidTemplateNames(): ?array { $validTemplates = null; $tDir = __DIR__ . DIR_TEMPLATE; if ($fh = opendir($tDir)) { while (false !== ($file = readdir($fh))) { if ($file != DOT and $file != DOTDOT and (substr($file, (strlen($file) - strlen(FILE_TYPE_INC))) == FILE_TYPE_INC)) { $validTemplates[] = preg_replace("/" . FILE_TEMPLATE_EXT . "/", "", $file); } } closedir($fh); } else { $msg = ERROR_READ_DIR . $tDir; static::$logger->warn($msg); } return($validTemplates); } /** * getTLTI() -- public static method * * This method was moved from gacFactory class to gasStatic class because the factory is not the only place where * we need to derive a TLTI based on a meta-data payload - this method will also be called from every broker * class when validating an incoming meta-data payload prior to the gacFactory instantiation. * * The method has the following input parameters: * * $_authToken -- this is the CLIENT_AUTH_TOKEN as received from the SMAX-request meta-data payload * $_eventGUID -- as above, except META_EVENT_GUID * $_payload -- call-by-reference parameter, will implicitly return the broker response payload * * We instantiate a read-broker client and, on success, build our query to fetch the TLTI from the SMAXAPI * data table in appServer. We'll exec the request as a system-level request to bypass redundant validation * checks speeding up the process. * * Next, we publish the request and consume the response -- if the event was successful, then we'll extract * the tlti from the payload and explicitly return that value. * * In all other cases, the function returns a null value to indicate a processing error. It's the responsibility * of the calling client to process the error which is why we implicitly return the response payload. * * * @author mike@givingassistant.org * @version 1.0 * * @param string $_authToken * @param string $_eventGUID * @param array|null $_payload * @return string|null * * * HISTORY: * ======== * 06-15-20 mks ECI-164: original coding as a tweaked-import from the gacFactory class * */ public static function getTLTI(string $_authToken, string $_eventGUID, ?array &$_payload = null):?string { // instantiate a read-broker client to fetch the TLTI for the AUTH TOKEN if (is_null($bc = static::getBC(BROKER_QUEUE_R, sprintf(INFO_LOC, basename(__FILE__), __LINE__)))) return null; $query = [STRING_KEY => [OPERAND_NULL => [OPERATOR_EQ => [$_authToken]]]]; $request = [ BROKER_REQUEST => BROKER_REQUEST_FETCH, BROKER_DATA => [ STRING_QUERY_DATA => $query, STRING_RETURN_DATA => [CM_SMAX_TLTI] ], BROKER_META_DATA => [ META_CLIENT => CLIENT_SYSTEM, META_DO_CACHE => false, META_TEMPLATE => TEMPLATE_CLASS_SMAXAPI, META_EVENT_GUID => $_eventGUID ] ]; // publish the payload request and consume the Namaste response $response = json_decode(gzuncompress($bc->call(gzcompress(json_encode($request)))), true); if (is_object($bc)) $bc->__destruct(); unset($bc); $_payload = $response; if ($response[PAYLOAD_STATUS] and $response[PAYLOAD_STATE] != STATE_NOT_FOUND) { if (isset($response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0][SMAX_TLTI])) { return $response[PAYLOAD_RESULTS][STRING_QUERY_RESULTS][0][SMAX_TLTI] . CHAR_T; } } return null; } /** * getBC() -- private static method * * This method was originally in the Factory class but was moved to the static class because of the broker calls * to validateMetaData also requires deriving the TLTI based on the META_CLIENT setting. * * This method fetches a valid broker client connecting to the appServer read broker. Since the instantiation * is exception wrapped, the call here is not. * * The method requires the following two input parameters: * * $_queue -- the name of the broker queue to instantiate * $_loc -- the INFO_LOC string which is passed to rabbit so as to identify where the request originated * * The method returns a gacBrokerClient object or, in the case of an error raised during instantiation, a null. * * * @author mike@givingassistant.org * @version 1.0 * * @param string $_queue * @param string $_loc * @return gacBrokerClient|null * * * HISTORY: * ======== * 06-15-20 mks ECI-164: original coding * */ private static function getBC(string $_queue, string $_loc):?gacBrokerClient { $file = sprintf(INFO_LOC, basename(__METHOD__), __LINE__); $bc = new gacBrokerClient($_queue, $_loc); if (!$bc->status) { // failed to instantiate a broker client $hdr = sprintf(INFO_LOC, $file, __LINE__); $msg = ERROR_BROKER_CLIENT_DECLARE . BROKER_QUEUE_R; consoleLog(static::$res, CON_SYSTEM, $hdr . $msg); static::$errors[] = $hdr . $msg; if (is_object($bc)) $bc->__destruct(); unset($bc); return null; } return $bc; } /** * buildPDODBName() -- public static method * * This method requires a single argument to the function: * * $_env: should be either ENV_PRIME, ENV_SEGUNDO or any of the other valid env names * * The purpose of this function is to generate the database name during run time which is predicated on the * current running environment and the current namaste service on which this is running. * * If an invalid or unsupported env is passed to the method, it will return a null. Otherwise, the method builds * the db name and returns that to the calling client. * * @author mike@givingassistant.org * @version 1.0 * * @param string $_env * @return string|null * * HISTORY: * ======== * 08-20-19 mks DB- */ public static function buildPDODBName(string $_env): ?string { $dbConfig = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_PDO]; // if more env's are defined to support PDO, you will have to also define them here. switch ($_env) { case ENV_APPSERVER : $namastePDO = $dbConfig[CONFIG_DATABASE_PDO_APPSERVER][CONFIG_DATABASE_PDO_MASTER][CONFIG_DATABASE_PDO_DB]; break; case ENV_SEGUNDO : $namastePDO = $dbConfig[CONFIG_DATABASE_PDO_SEGUNDO][CONFIG_DATABASE_PDO_MASTER][CONFIG_DATABASE_PDO_DB]; break; default : consoleLog(static::$res, CON_ERROR, sprintf(ERROR_RESOURCE_ENV_404, STRING_PDO, $_env)); return null; break; } return gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] . UDASH . $namastePDO; } /** * getSysLogError() -- public static method * * This method requires one input parameter: * * $_error: integer value representing the namaste error * * Namaste errors are mapped as follows: * * Namaste Error Value Syslog Error * --------------------------------------- * DEBUG 2 LOG_DEBUG * DATA 3 LOG_NOTICE * INFO 4 LOG_INFO * ERROR 5 LOG_ERROR * WARN 6 LOG_CRIT * FATAL 7 LOG_EMERG * * TRACE used to be Value = 1 but has since been deprecated. * METRICS has a Value of 0. * EVENT has a value of -1. * * We create a simple matrix with the Namaste values as keys and the sysLog values as values and then map the * input value passed in $_error via the matrix. If not found, then we return a LOG_ERR syslog code. Otherwise, * return the mapped integer value. * * * @author mike@givingassistant.org * @version 1.0 * * @param int $_error * @return int * * HISTORY: * ======== * 09-26-19 mks DB-136: original coding * */ public static function getSysLogError(int $_error): int { $matrix = [ 2 => LOG_DEBUG, 3 => LOG_NOTICE, 4 => LOG_INFO, 5 => LOG_ERR, 6 => LOG_CRIT, 7 => LOG_EMERG ]; return (!array_key_exists($_error, $matrix)) ? LOG_ERR : $matrix[$_error]; } }