Archive: Namaste PHP AMQP framework v1.0 (2017-2020)
952 days continuous production uptime, 40k+ tp/s single node. Original corpo Bitbucket history not included — clean archive commit.
This commit is contained in:
315
classes/deprecated/gaaNamasteCore.class.txt
Normal file
315
classes/deprecated/gaaNamasteCore.class.txt
Normal file
@@ -0,0 +1,315 @@
|
||||
/**
|
||||
* convertCacheMapDataToSchema() -- protected method
|
||||
*
|
||||
* this method takes an input array of payload data and checks to see if the current-loaded class has cacheMapping
|
||||
* set (the cacheMap element has to be an array) and uses the map to convert the data from the public (cachemap)
|
||||
* to private (schema) format.
|
||||
*
|
||||
* method requires two input parameters:
|
||||
*
|
||||
* - the payload data - which is a indexed array of associative array tuples
|
||||
* - boolean toggle indicating if ALL fields are required to pass validation
|
||||
*
|
||||
* If the current class has cacheMapping, then we're going to spin through each tuple in the $_data parameter
|
||||
* and look at each $key in the tuple -- if the $key exists as a member in the cacheMap, pull the key from cacheMap
|
||||
* and store the new key and the old value in a temp array. If the key does not exist in the cacheMap then
|
||||
* use the current (old) key/value pair.
|
||||
*
|
||||
* After each tuple is processed,copy the new vector in to a temporary matrix which will eventually be returned
|
||||
* to the calling client.
|
||||
*
|
||||
* in all other (fail) cases, a null is returned.
|
||||
*
|
||||
* NOTE:
|
||||
* -----
|
||||
* This method is not to be confused with gasCache->buildMappedDataArray() which converts schema to cacheMap.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_data
|
||||
* @param bool $_allFields
|
||||
* @return null|array
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-13-17 mks CORE-464: original coding
|
||||
* 02-06-18 mks _INF-139: support for disabled caching + no cache map
|
||||
* 02-22-18 mks _INF-139: when cache is disabled, need to verify that submitted data included the class
|
||||
* extension - if not, replace the old key with the old key + class extension
|
||||
* 12-12-18 mks DB-77: fixed error in processing: when we have a journal recovery event, the restore
|
||||
* query uses column literals instead of cache-mapped values. Added conditional code
|
||||
* to check if the literal appears in the field list and, if so, validate that field
|
||||
*/
|
||||
protected function convertCacheMapDataToSchema(array $_data, bool $_allFields = false): ?array
|
||||
{
|
||||
$this->state = STATE_VALIDATION_ERROR;
|
||||
$this->status = false;
|
||||
$data = false;
|
||||
$badData = false;
|
||||
|
||||
$loggerAvailable = (isset($this->logger) and $this->logger->available);
|
||||
|
||||
if (!is_array($_data)) {
|
||||
$msg = basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_DATA_INVALID_FORMAT;
|
||||
if ($loggerAvailable)
|
||||
$this->logger->data($msg);
|
||||
else
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
} elseif ($this->useCache and empty($this->cacheMap)) {
|
||||
$msg = ERROR_CACHE_MAP_404 . COLON . $this->class;
|
||||
if ($loggerAvailable)
|
||||
$this->logger->data($msg);
|
||||
else
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
} elseif (!$this->useCache and (!isset($this->cacheMap) or empty($this->cacheMap))) {
|
||||
$data = $_data[0];
|
||||
foreach ($data as $key => $value) {
|
||||
try {
|
||||
$newKey = $this->addExtension($key);
|
||||
} catch (TypeError $t) {
|
||||
$msg = ERROR_TYPE_EXCEPTION . COLON . $t->getMessage();
|
||||
if ($loggerAvailable)
|
||||
$this->logger->error($msg);
|
||||
else
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
return null;
|
||||
}
|
||||
if (is_null($newKey)) return null;
|
||||
if ($newKey != $key) {
|
||||
$data[$newKey] = $value;
|
||||
unset($data[$key]);
|
||||
}
|
||||
}
|
||||
$this->state = STATE_SUCCESS;
|
||||
$this->status = true;
|
||||
return [$data];
|
||||
} else {
|
||||
$counter = 0;
|
||||
for ($index = 0, $last = count($_data); $index < $last; $index++) {
|
||||
$row = null;
|
||||
foreach ($_data[$index] as $key => $value) {
|
||||
$ck = array_search($key, $this->cacheMap);
|
||||
if (false === $ck) {
|
||||
$ck = array_key_exists($key, $this->cacheMap);
|
||||
/*
|
||||
* edge case - this case will be encountered in situations where we're using non-cache-mapped
|
||||
* keys (e.g.: column literals) in a cached-class query where there exists a cache-map.
|
||||
* Journaling saves the recovery query in literal (as opposed to cache-mapped) format... so, we
|
||||
* need to accommodate the possibility where the data keys exist only in the $fieldList member
|
||||
* and, if so, treat the keys as valid values once we've exhausted cache-map processing
|
||||
*/
|
||||
if (false === $ck) { // check to see if key is member of $fieldList
|
||||
// first - see if we have an extension appended to the key - if not, add one
|
||||
$newKey = $this->addExtension($key);
|
||||
// then, check if the qualified key exists in the fieldList - if so, update the value of $ck
|
||||
$ck = (in_array($newKey, $this->fieldList)) ? $newKey : false;
|
||||
}
|
||||
if (false === $ck) {
|
||||
$msg = ERROR_DATA_INVALID_KEY . $key;
|
||||
$this->eventMessages[] = $msg;
|
||||
if ($loggerAvailable)
|
||||
$this->logger->data($msg);
|
||||
else
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
if ($_allFields) $badData = true;
|
||||
$ck = $key;
|
||||
}
|
||||
}
|
||||
if (is_array($value) and !empty($this->subCollections) and array_key_exists($ck, $this->subCollections)) {
|
||||
try {
|
||||
$value = $this->convertCacheMapDataToSchema($value);
|
||||
} catch (TypeError $t) {
|
||||
$msg = ERROR_TYPE_EXCEPTION . COLON . $t->getMessage();
|
||||
if ($loggerAvailable)
|
||||
$this->logger->error($msg);
|
||||
else
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
return null;
|
||||
}
|
||||
if (false === $value) {
|
||||
$msg = sprintf(ERROR_SUB_C_V_NULL, $ck);
|
||||
$this->logger->warn($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
}
|
||||
}
|
||||
if (false !== $ck) $row[$ck] = $value;
|
||||
}
|
||||
if (!empty($row)) $data[$counter++] = $row;
|
||||
}
|
||||
if (($_allFields and !$badData and is_array($data)) or (!$_allFields and is_array($data))) {
|
||||
$this->state = STATE_SUCCESS;
|
||||
$this->status = true;
|
||||
}
|
||||
}
|
||||
return( ($this->status) ? $data : null );
|
||||
}
|
||||
|
||||
NOTE: dataScrub() wasn't deprecated, just eviscerated...
|
||||
|
||||
/**
|
||||
* dataScrub() -- private method
|
||||
*
|
||||
* this method parses all of the data stored in the protected $data member and replaces keys with cleaned values
|
||||
* (extensions stripped from keys) and critical values removed entirely.
|
||||
*
|
||||
* $_data -- call-by-reference variable that's the implicitly returned
|
||||
*
|
||||
* While processing the data rows, we make a recursive call back to this method if we encounter sub-arrays so
|
||||
* that the sub-array keys can be stripped (method 1 only!) also.
|
||||
*
|
||||
* When generating the return data, for every row of data, we check each column to ensure it's not listed in the
|
||||
* $hiddenColumns member array and, if it is, we remove it.
|
||||
*
|
||||
* For nosql-based collections, if we specify that we want the meta data, then we'll return the history
|
||||
* sub-collection (aka meta data) so if meta isn't specified, the meta is dropped from the return set.
|
||||
*
|
||||
* There are no errors raised in this method. The success is implicitly defined in the $_data return structure.
|
||||
*
|
||||
* NOTE:
|
||||
* =====
|
||||
* Cache-Key Mapping is located in the private static method gasCache::buildMappedDataArray().
|
||||
*
|
||||
*
|
||||
* @author mikegivingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $_data
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-22-17 mks original coding
|
||||
* 08-14-17 mks CORE-493: removing meta param support (DB_HISTORY no longer supported)
|
||||
*
|
||||
*/
|
||||
private function dataScrub(array &$_data): void
|
||||
{
|
||||
if (empty($_data)) {
|
||||
$msg = ERROR_DATA_MISSING_ARRAY . STRING_DATA;
|
||||
$this->eventMessages[] = $msg;
|
||||
if (isset($this->logger) and $this->logger->available)
|
||||
$this->logger->error($msg);
|
||||
else
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* if we're requesting a clean data set, and we've not requested a key-mapping, then
|
||||
* clean the data "old-school" style, stripping off extensions, pulling the mongo ID
|
||||
* fields, in the return data set.
|
||||
*/
|
||||
for ($index = 0, $last = count($_data); $index < $last; $index++) {
|
||||
if (!empty($_data[$index]) and is_array($_data[$index])) {
|
||||
foreach ($_data[$index] as $key => $value) {
|
||||
$newKey = str_replace($this->ext, '', $key);
|
||||
if (is_array($value)) {
|
||||
try {
|
||||
$this->dataScrub($value);
|
||||
} catch (TypeError $t) {
|
||||
$msg = basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_TYPE_EXCEPTION . COLON . $t->getMessage();
|
||||
$this->eventMessages[] = $msg;
|
||||
if (isset($this->logger) and $this->logger->available)
|
||||
$this->logger->error($msg);
|
||||
else
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if ($newKey != $key and !in_array($newKey, $this->hiddenColumns)) {
|
||||
$_data[$index][$newKey] = $value;
|
||||
unset($_data[$index][$key]);
|
||||
} elseif (in_array($newKey, $this->hiddenColumns)) {
|
||||
unset($_data[$index][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* cmData() -- public function
|
||||
*
|
||||
* This public function is a dirty little way to stuff whatever data is defined in $_payload to replace whatever
|
||||
* is stored in the protected member: $data.
|
||||
*
|
||||
* The only requirement is that the input parameter be an array.
|
||||
*
|
||||
* The purpose of this method is to store the cacheMap key(s) into the $data payload right before the broker
|
||||
* event, that generated the data payload, finished processing an releases the class memory assigned to the object.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_payload
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-04-19 mks DB-116: original coding
|
||||
*
|
||||
*/
|
||||
public function cmData(array $_payload): void
|
||||
{
|
||||
$this->data = $_payload;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* dumpRecord() -- public core method
|
||||
*
|
||||
* Sometimes, you need to know what's in the $data payload and, since it's protected, you can't access it directly
|
||||
* without going through one of the other methods that filters the payload.
|
||||
*
|
||||
* This method allows you to dump a row of data from the $data array to stdout. If you don't specify a row (as
|
||||
* the only input parameter, then you will dump the first (0th) row in the array. However, if the array is empty,
|
||||
* we'll out a message to that effect.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param int $_row
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-24-18 mks DB-67: original coding
|
||||
*
|
||||
*
|
||||
*/
|
||||
public function dumpRecord(int $_row = 0): void
|
||||
{
|
||||
if (empty($this->data))
|
||||
echo INFO_NO_DATA_IN_DATA;
|
||||
else
|
||||
var_export($this->data[$_row]);
|
||||
}
|
||||
|
||||
/**
|
||||
* validateStatus() -- public method
|
||||
*
|
||||
* Simple method that takes a single input parameter, a string, and returns a boolean value corresponding to
|
||||
* whether or not the string-value is present in the validStatus member array.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_status
|
||||
* @return bool
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-12-18 mks _INF-139: original coding
|
||||
*
|
||||
*/
|
||||
public function validateStatus(string $_status): bool
|
||||
{
|
||||
return (in_array($_status, $this->validStatus));
|
||||
}
|
||||
143
classes/deprecated/gacAdminClient.txt
Normal file
143
classes/deprecated/gacAdminClient.txt
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* this class is used when we want to publish a request to the AdminIn broker. The class wraps all of the
|
||||
* RabbitMQ initialization and communication work so you don't have to. Especially useful for unit testing.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks original coding
|
||||
* 07-05-17 mks eliminated recursive calls to the $logger entity; replaced $logger calls with console output
|
||||
*
|
||||
*/
|
||||
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
use /** @noinspection PhpUnusedAliasInspection */ PhpAmqpLib\Message\AMQPMessage;
|
||||
|
||||
class gacAdminClientIn
|
||||
{
|
||||
/** @var PhpAmqpLib\Connection\AMQPStreamConnection */
|
||||
private $rabbitConnection;
|
||||
/** @var PhpAmqpLib\Channel\AMQPChannel */
|
||||
private $rabbitChannel;
|
||||
private $rabbitCorrelationID;
|
||||
private $rabbitCallbackQueue;
|
||||
private $queueName;
|
||||
private $res = 'BACI: '; // Broker Admin Client In
|
||||
public $status;
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* this is the constructor for the class. it requests an admin resource from the resource manager and declares
|
||||
* a client-side connection to the service.
|
||||
*
|
||||
* there is an optional input parameter -- $_fw (from-where) that inserts a string into the queue label allowing
|
||||
* easy identification of the requesting source.
|
||||
*
|
||||
* the method returns no values. It only sets the class' status member variable, a Boolean, on success or fail,
|
||||
* accordingly.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* @param $_fw - "from where" - tweaks queue label to identify request origin
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __construct($_fw = 'AdminClientIn')
|
||||
{
|
||||
register_shutdown_function(array($this, STRING_DESTRUCTOR));
|
||||
$this->status = false;
|
||||
|
||||
var_dump(debug_backtrace());
|
||||
$this->queueName = gasResourceManager::$cfgAdmin[CONFIG_BROKER_QUEUE_TAG] . BROKER_QUEUE_AI;
|
||||
// $this->rabbitConnection = gasResourceManager::fetchResource(RESOURCE_ADMIN);
|
||||
$this->rabbitConnection = new AMQPStreamConnection('localhost', 5672, 'namaste', 'oSZL8Cby', 'mdev');
|
||||
if (is_null($this->rabbitConnection)) return;
|
||||
$this->rabbitChannel = $this->rabbitConnection->channel();
|
||||
$label = uniqid('gacAdminInClient<' . $_fw . '>:');
|
||||
list($this->rabbitCallbackQueue, ,) = $this->rabbitChannel->queue_declare($label, false, false, false, false); // was: f,f,f,t
|
||||
$this->status = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* call() -- public method
|
||||
*
|
||||
* This method is invoked outside of the class and is the entry point for publishing a message request to the
|
||||
* AdminIn broker. It creates a new AMQP message and publishes it to the queue (defined in the constructor),
|
||||
* and then exits, returning a true message indicating that the messages was successfully published.
|
||||
*
|
||||
* Since the AdminIN broker is a fire-n-forget broker, there are no return messages to block-and-wait on.
|
||||
*
|
||||
* If an exception is raised by this class, then a false value will be returned.
|
||||
*
|
||||
* NOTE: the true/false return values are not, in any way, a reflection of the processing success/failure on the
|
||||
* remote service. The general RoT is that if we can publish the request, then we can only assume that the request
|
||||
* was successfully consumed and processed.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $_data
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function call($_data)
|
||||
{
|
||||
$this->rabbitCorrelationID = uniqid();
|
||||
$res = false;
|
||||
$rabbitMessage = new AMQPMessage((string)$_data);
|
||||
try {
|
||||
$rabbitMessage = new AMQPMessage((string)$_data, array(BROKER_CORRELATION_ID => $this->rabbitCorrelationID, BROKER_REPLY_TO => $this->rabbitCallbackQueue));
|
||||
|
||||
$this->rabbitChannel->basic_publish($rabbitMessage, '', $this->queueName);
|
||||
$res = true;
|
||||
} catch (AMQPTimeoutException $e) {
|
||||
echo getDateTime() . CON_ERROR . $this->res . ERROR_BROKER_EXCEPTION_TIMEOUT . PHP_EOL;
|
||||
echo getDateTime() . CON_ERROR . $this->res . $e->getMessage() . PHP_EOL;
|
||||
} catch (\PhpAmqpLib\Exception\AMQPRuntimeException $e) {
|
||||
echo getDateTime() . CON_ERROR . $this->res . ERROR_BROKER_EXCEPTION_RUNTIME . PHP_EOL;
|
||||
echo getDateTime() . CON_ERROR . $this->res . $e->getMessage() . PHP_EOL;
|
||||
} catch (AMQPException $e) {
|
||||
echo getDateTime() . CON_ERROR . $this->res . ERROR_BROKER_EXCEPTION . PHP_EOL;
|
||||
echo getDateTime() . CON_ERROR . $this->res . $e->getMessage() . PHP_EOL;
|
||||
} catch (Exception $e) {
|
||||
echo getDateTime() . CON_ERROR . $this->res . ERROR_BROKER_EXCEPTION . PHP_EOL;
|
||||
echo getDateTime() . CON_ERROR . $this->res . $e->getMessage() . PHP_EOL;
|
||||
}
|
||||
$this->rabbitChannel->close();
|
||||
$this->rabbitConnection->close();
|
||||
$this->status = $res;
|
||||
}
|
||||
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
// As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
//
|
||||
// destructor is registered shut-down function in constructor -- so any recovery
|
||||
// efforts should go in this method.
|
||||
if (is_object($this->rabbitChannel)) {
|
||||
$this->rabbitChannel->close();
|
||||
$this->rabbitConnection->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
149
classes/deprecated/gacErrorLogger.class.txt
Normal file
149
classes/deprecated/gacErrorLogger.class.txt
Normal file
@@ -0,0 +1,149 @@
|
||||
/**
|
||||
* getNoSQLResource() -- private static method
|
||||
*
|
||||
* this method initializes the nosql resource by attempting to connect to the nosql service. if the connection
|
||||
* attempt succeeds, then mark the resource as available. Otherwise, post an error-fatal and explicitly mark
|
||||
* the service as not-available and return.
|
||||
*
|
||||
* NOTE:
|
||||
* -----
|
||||
* This resource allocation exists outside of the resource manager because the resource manager instantiates
|
||||
* this class in it's constructor. Were you to request a resource from the resource manager, you'd end-up in
|
||||
* a circular reference and if the whole thing does not come to an immediate shuddering stop, then it would
|
||||
* certainly blow-up the first time you attempt to log an error. So, tl;dr: do not attempt to 'fix' this as
|
||||
* it's not broken.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return Aws\DynamoDb\DynamoDbClient|null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-09-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function getNoSQLResource():Aws\DynamoDb\DynamoDbClient
|
||||
{
|
||||
global $eos;
|
||||
$options = null;
|
||||
date_default_timezone_set(TIME_TIMEZONE);
|
||||
|
||||
if (empty($this->config)) {
|
||||
echo getDateTime() . CON_ERROR . $this->res . ERROR_CONFIG_RESOURCE_404 . CONFIG_DATABASE_DDB . $eos;
|
||||
return(null);
|
||||
}
|
||||
|
||||
$noSQLConfig = $this->config[CONFIG_DATABASE_DDB_APPSERVER];
|
||||
$credentials = [
|
||||
STRING_KEY => $noSQLConfig[CONFIG_DATABASE_DDB_APPSERVER_KEY_ID],
|
||||
STRING_SECRET => $noSQLConfig[CONFIG_DATABASE_DDB_APPSERVER_ACCESS_KEY]
|
||||
];
|
||||
|
||||
/*
|
||||
* Requests to DynamoDB are made over HTTP(S), and this does not require that you establish an upfront
|
||||
* connection. When you create the client object, you are not making a connection to DynamoDB, you are just
|
||||
* configuring an HTTP client that will make requests to DynamoDB.
|
||||
*/
|
||||
|
||||
$awsConfig = new Aws\Sdk([
|
||||
STRING_ENDPOINT => $noSQLConfig[CONFIG_DATABASE_DDB_APPSERVER_DSN] . ':' . $noSQLConfig[CONFIG_DATABASE_DDB_APPSERVER_PORT],
|
||||
STRING_REGION => $noSQLConfig[CONFIG_DATABASE_DDB_APPSERVER_REGION],
|
||||
STRING_VERSION => $noSQLConfig[CONFIG_DATABASE_DDB_APPSERVER_VERSION],
|
||||
STRING_CREDS => $credentials
|
||||
]);
|
||||
return $awsConfig->createDynamoDb();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getLog() - public method
|
||||
*
|
||||
* getLog is the method that is used to fetch log (or Metrics) records from the mongo collection.
|
||||
*
|
||||
* because ddb limits queries to 1MB returns, and the paint is still wet on this schema, for now I'm
|
||||
* going to limit queries for log-file fetching to just the last N records created within the last hour and
|
||||
* we'll just grab up to the limit of the records returned - which should still be a significant number of
|
||||
* records...
|
||||
*
|
||||
* This method reads the last X records created in the last hour (since this method is mainly used for
|
||||
* providing HTML output to the log-reader) and wraps the data in HTML table rows intended for the logDump
|
||||
* utility.
|
||||
*
|
||||
* todo -- pagination support? Query by error-code? Query by eventID? Query by class?
|
||||
*
|
||||
* @author mshallop@pathway.com
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_what defaults to the log template -- should be over-ridden for metrics template
|
||||
* @return null|string
|
||||
* @throws Exception
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
* 06-14-17 mks refactored for ddb
|
||||
*
|
||||
*/
|
||||
public function getLog(string $_what = TEMPLATE_CLASS_LOGS):string
|
||||
{
|
||||
$result = null;
|
||||
$returnData = null;
|
||||
$marshaler = new Marshaler(); // black-box son converter
|
||||
$lastHour = time() - NUMBER_ONE_HOUR_SEC;
|
||||
if ($_what != TEMPLATE_CLASS_LOGS and $_what != TEMPLATE_CLASS_METRICS) $_what = TEMPLATE_CLASS_LOGS;
|
||||
|
||||
$eav = $marshaler->marshalJson('{":ts" :' . $lastHour . '}');
|
||||
|
||||
$params = [
|
||||
DDB_STRING_TABLE_NAME => $this->collectionName,
|
||||
DDB_STRING_KEY_COND_EXPR => LOG_CREATED . ' > :ts',
|
||||
DDB_STRING_EXPR_ATTR_VALS => $eav
|
||||
];
|
||||
|
||||
try {
|
||||
$result = $this->connection->query($params);
|
||||
} catch (DynamoDbException $e) {
|
||||
$this->errStack[] = __FILE__ . ':' . __LINE__ . ':' . __METHOD__ . ':' . $this->class . ':' .
|
||||
ERROR_FATAL . ' caught cursor exception: ' . $e->getMessage();
|
||||
self::throwFatal();
|
||||
}
|
||||
if (!is_null($result)) {
|
||||
foreach ($result[DDB_STRING_ITEMS] as $row) {
|
||||
$returnData .= '<div class="rowMeta">'; // note: css is defined in the utilities directory
|
||||
$returnData .= '(' . $row[(DB_PKEY . $this->ext)] . ') - ';
|
||||
// $returnData .= date(TIME_DATE_FORMAT, $row[(META_SESSION_DATE . self::$ext)]->sec) . ' - ';
|
||||
|
||||
// add error label as a span: warn/error/fatal...
|
||||
$returnData .= self::getErrorLabel($row[(LOG_LEVEL . $this->ext)]);
|
||||
|
||||
$returnData .= ' ' . $row[(ERROR_FILE . $this->ext)] . '(' . $row[(ERROR_LINE . $this->ext)] . ')';
|
||||
$cd = '';
|
||||
if (!empty($row[(ERROR_CLASS . $this->ext)])) $cd = ' class[' . $row[(ERROR_CLASS . $this->ext)] . ']';
|
||||
if (!empty($row[(ERROR_METHOD . $this->ext)])) $cd .= '.method(' . $row[(ERROR_METHOD . $this->ext)] . ')</div>';
|
||||
$returnData .= $cd;
|
||||
/*
|
||||
if ($row[(ERROR_TYPE . self::$ext)] == ERROR_TRACE) {
|
||||
$returnData .= '</div>';
|
||||
}
|
||||
*/
|
||||
$returnData .= '<div class="rowData">' . htmlentities($row[(ERROR_MESSAGE . $this->ext)]);
|
||||
if ($_what == TEMPLATE_CLASS_METRICS) {
|
||||
$returnData .= ' - ' . $row[(DB_TIMER . $this->ext)] . ' or ';
|
||||
$returnData .= ($row[(DB_TIMER . $this->ext)] * NUMBER_MS_PER_SEC) . 'ms';
|
||||
}
|
||||
$returnData .= '</div>';
|
||||
$returnData .= '<div class="rowHist">';
|
||||
foreach($row[(DB_HISTORY . $this->ext)] as $histRec) {
|
||||
$returnData .= date('Y-M-d h:i:s', $histRec[META_SESSION_DATE]->sec);// . ' (';
|
||||
if (!is_null($row[(LOG_EVENT_GUID . $this->ext)]))
|
||||
$returnData .= ', Event ID: ' . $row[(LOG_EVENT_GUID . $this->ext)];
|
||||
// $returnData .= $histRec[META_SESSION_EVENT] . ') from (';
|
||||
// $returnData .= $histRec[META_SESSION_IP] . '): ';
|
||||
// $returnData .= ((isset($histRec[META_SESSION_ID])) ? $histRec[META_SESSION_ID] : $histRec[META_CLIENT]) . '<br />';
|
||||
}
|
||||
$returnData .= '</div><br />';
|
||||
}
|
||||
}
|
||||
return ($returnData);
|
||||
}
|
||||
68
classes/deprecated/gacMeta.class.txt
Normal file
68
classes/deprecated/gacMeta.class.txt
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
|
||||
/**
|
||||
* validateMeta() -- public method
|
||||
*
|
||||
* This method requires one input parameter:
|
||||
*
|
||||
* $_meta -- a key-value paired array containing the current meta data payload
|
||||
*
|
||||
* first we validate the input parameter to ensure we're working with valid data object. If not, we're going to
|
||||
* immediately return a false value and set the gacMetrics property (stopProcessing) to true. This allows us
|
||||
* to signal the gacFactory class that a processing error had occurred.
|
||||
*
|
||||
* Otherwise, spin through the meta data that was passed to the method and compare each key in the array to the
|
||||
* list of "authorized" keys defined for the current class. If a key does not exist in the authoritative index,
|
||||
* then remove that key from the input-meta data and record the event in the log file and in the gacFactory
|
||||
* class eventMessages property.
|
||||
*
|
||||
* Method returns a boolean value that indicates if meta data was validated.
|
||||
*
|
||||
* Since the meta data array is passed as a call-by-reference variable, dropped fields will propagate back to the
|
||||
* calling client. A list of dropped fields, if any, will be stored in the eventMessages container.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_meta
|
||||
* @return bool
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-21-17 mks original coding
|
||||
* 10-05-17 mks CORE-584: added validation for META_SKIP and META_LIMIT
|
||||
*
|
||||
*/
|
||||
public function validateMeta(array &$_meta):bool
|
||||
{
|
||||
if (!is_array($_meta) or empty($_meta)) {
|
||||
$this->logger->error(ERROR_DATA_META_REQUIRED);
|
||||
$this->eventMessages[] = ERROR_DATA_META_REQUIRED;
|
||||
return(false);
|
||||
}
|
||||
foreach ($_meta as $key => $value) {
|
||||
if (!array_key_exists($key, $this->fields)) {
|
||||
unset($_meta[$key]);
|
||||
$msg = sprintf(NOTICE_META_DISCARD, $key);
|
||||
$this->eventMessages[] = $msg;
|
||||
if ($this->debug) $this->logger->debug($msg);
|
||||
} else {
|
||||
switch ($key) {
|
||||
case META_SKIP :
|
||||
case META_LIMIT :
|
||||
if (!is_numeric($value)) {
|
||||
$msg = ERROR_DATA_FIELD_DROPPED . $key;
|
||||
$this->eventMessages[] = $msg;
|
||||
if ($this->debug) $this->logger->debug($msg);
|
||||
$msg = sprintf(ERROR_DATA_TYPE_MISMATCH_DETAILS, $key, DATA_TYPE_INTEGER, gettype($value));
|
||||
$this->eventMessages[] = $msg;
|
||||
if ($this->debug) $this->logger->debug($msg);
|
||||
unset($_meta[$key]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
55
classes/deprecated/gacMongoDB.class.txt
Normal file
55
classes/deprecated/gacMongoDB.class.txt
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
|
||||
/**
|
||||
* deBSON() -- private method
|
||||
*
|
||||
* MongoDB has a problem fetching data as it tends to BSON serialize all properties within a record for
|
||||
* non-packed record arrays. So, this method, which is recursive, takes the current data payload of N-records,
|
||||
* and traverses all the records looking for declared array fields (fieldTypes).
|
||||
*
|
||||
* When found, that field type is force-cast to type = array and, if the field itself is another array, such
|
||||
* as a sub-collection, the method will recursively call itself.
|
||||
*
|
||||
* As of this time, version 1.0.0, this method is only called from the _fetchRecords() method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $_data
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-29-17 mks CORE-494: original coding
|
||||
* 11-26-18 mks DB-55: added error processing if a key is not a member of the current class
|
||||
*
|
||||
*/
|
||||
private function deBSON(&$_data)
|
||||
{
|
||||
if (is_array($_data) and array_key_exists(0, $_data)) {
|
||||
for ($index = 0, $limit = count($_data); $index < $limit; $index++) {
|
||||
foreach ($_data[$index] as $column => &$value) {
|
||||
if ($this->fieldTypes[$column] == DATA_TYPE_ARRAY) {
|
||||
if (!is_scalar($value)) {
|
||||
foreach ($value as &$rec) {
|
||||
if (!is_scalar($rec)) $rec = (array) $rec;
|
||||
}
|
||||
$this->deBSON($value);
|
||||
}
|
||||
$_data[$index][$column] = (array) $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif (is_array($_data)) {
|
||||
foreach ($_data as $key => $val) {
|
||||
if (array_key_exists($key, $this->fieldTypes) and $this->fieldTypes[$key] == DATA_TYPE_ARRAY) {
|
||||
if (is_array($val))
|
||||
$this->deBSON($val);
|
||||
$_data[$key] = (array) $val;
|
||||
} elseif (!array_key_exists($key, $this->fieldTypes)) {
|
||||
$msg = ERROR_DATA_FIELD_NOT_MEMBER . $key;
|
||||
$this->eventMessages[] = sprintf(STUB_LOC, basename(__FILE__),__METHOD__, __LINE__) . COLON . $msg;
|
||||
$this->logger->data($msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
709
classes/deprecated/gacMySQL.class.inc
Normal file
709
classes/deprecated/gacMySQL.class.inc
Normal file
@@ -0,0 +1,709 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BindParams -- helper class
|
||||
*
|
||||
* this is a helper class for the gacMySQL class, specifically for generating dynamic prepared statements.
|
||||
*
|
||||
* this class, when instantiated, creates storage for a prepared statement's type and values. When we want to
|
||||
* create the prepared statement, we use call_user_func_array() and use the output from this method to generate
|
||||
* the arguments that are normally passed in a prepared statement.
|
||||
*
|
||||
* using this class allows a data payload to be dynamically parsed and validated - allows a client to update
|
||||
* a sub-set of a table without having to explicitly enumerate every column in the table.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* --------
|
||||
* 06-29-17 mks original coding
|
||||
*
|
||||
*/
|
||||
class BindParams {
|
||||
private $values = array();
|
||||
private $types = '';
|
||||
|
||||
/**
|
||||
* add() -- public method
|
||||
*
|
||||
* this method accepts two parameters as input - the type of the variable and the value of the variable. In
|
||||
* this instance, when I say variable, I am referring to a mysql table column.
|
||||
*
|
||||
* if, for some unknown reason, type is a value not allowed, reset it to type 's' which should cover-up most
|
||||
* mistakes.
|
||||
*
|
||||
* $value as a call-by-reference to suppress a PHP warning message.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $type
|
||||
* @param $value
|
||||
*
|
||||
* HISTORY:
|
||||
* --------
|
||||
* 06-29-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function add(string $type, &$value)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'd' :
|
||||
case 'i' :
|
||||
case 'b' :
|
||||
case 's' :
|
||||
break;
|
||||
default :
|
||||
$type = 's';
|
||||
}
|
||||
$this->values[] = $value;
|
||||
$this->types .= $type;
|
||||
}
|
||||
|
||||
public function isEmpty()
|
||||
{
|
||||
return((empty($this->values)) ? true : false);
|
||||
}
|
||||
|
||||
public function checkOrd()
|
||||
{
|
||||
return((count($this->values) == strlen($this->types)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* get() -- public method
|
||||
*
|
||||
* get() simply returns the two class variables as a string of output that's tailored to the input
|
||||
* requirement of mysqli::bind_param().
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* HISTORY:
|
||||
* --------
|
||||
* 06-29-17 mks Original coding
|
||||
*
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return array_merge(array($this->types), $this->values);
|
||||
}
|
||||
|
||||
public function refValues($arr) {
|
||||
$refs = array();
|
||||
foreach($arr as $key => $value)
|
||||
$refs[$key] = &$arr[$key];
|
||||
return $refs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class gacMySQL extends gaaNamasteCore
|
||||
{
|
||||
private $slaveConnection = null; // resource link to mysqli service
|
||||
protected $useSlaveServer = false; // should be overridden in the class instantiation
|
||||
protected $batchSize = PDO_RECORDS_PER_PAGE;
|
||||
protected $mySqlTypes = array();
|
||||
protected $tip = false; // indicates if a transaction is already in progress
|
||||
protected $uniqueIndexes = null;
|
||||
protected $compoundIndexes = null;
|
||||
protected $exposedFields = null;
|
||||
protected $dbEvent; // used to track the different sql events
|
||||
protected $rowsAffected; // how many rows were affected by the sql query
|
||||
protected $queryResult; // container to hold return payload from mysqli
|
||||
protected $recordLimit;
|
||||
protected $serviceReady; // boolean indicating if the mysql service is ready
|
||||
|
||||
// exceptions to the query-builder
|
||||
public $queryOrderBy;
|
||||
public $queryOrderByDirection;
|
||||
public $queryGroupBy;
|
||||
public $queryGroupByDirection;
|
||||
public $queryLimit;
|
||||
public $queryHaving;
|
||||
public $mysqlMasterAvailable;
|
||||
public $mysqlSlaveAvailable;
|
||||
|
||||
// allowable operands for mysql
|
||||
public $operands = [
|
||||
OPERATOR_EQ,
|
||||
OPERATOR_LTE,
|
||||
OPERATOR_GTE,
|
||||
OPERATOR_DNE,
|
||||
OPERATOR_LT,
|
||||
OPERATOR_GT,
|
||||
OPERATOR_NE
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* __construct -- public method
|
||||
*
|
||||
* constructor for the mysql data instantiation class
|
||||
*
|
||||
* Three input parameters are supported for the constructor:
|
||||
*
|
||||
* $_template: the name of the template that establishes which data class will be instantiated
|
||||
* $_meta: the meta data payload as received from the broker - critical because it contains the name
|
||||
* of the class template we're going to be instantiating.
|
||||
* $_id: an optional parameter - if provided, we'll instantiate the class and then attempt to load
|
||||
* the record referenced by the primary key value (after evaluating the id type).
|
||||
*
|
||||
* Next, we going to assign mysql resources - based on the configuration, if we're supporting slave reads, make
|
||||
* the appropriate assignments so the correct resource is engaged for any particular query.
|
||||
*
|
||||
* Load the template properties into the class and set the class properties accordingly.
|
||||
*
|
||||
* Every mySQL table has two "primary keys" -- the traditional auto-incrementing integer, and a guid string.
|
||||
* The best-practices effort of "id's internally, guids externally" applies to mysql structures.
|
||||
*
|
||||
* When we instantiate the class and we receive an id, we have to evaluate if we're passed a string (guid) or an
|
||||
* integer (id) and adjust the current pkey pointer appropriately so that correct query is build deeper down.
|
||||
*
|
||||
* Therefore, mysql is the first and, of this writing, the only db instantiation class that has a floating pkey
|
||||
* value/type which is established on a data fetch at run-time.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0.0
|
||||
*
|
||||
* @param string $_template
|
||||
* @param array $_meta
|
||||
* @param mixed $_id
|
||||
*
|
||||
* HISTORY:
|
||||
* --------
|
||||
* 06-29-17 mks initial coding
|
||||
*
|
||||
*/
|
||||
public function __construct(string $_template, array $_meta, $_id = null)
|
||||
{
|
||||
register_shutdown_function(array($this, '__destruct'));
|
||||
|
||||
parent::__construct();
|
||||
|
||||
if ($this->trace and $this->logger->available) {
|
||||
$this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
if (!empty($_guid) and $this->debug) {
|
||||
$this->logger->debug('received guid: ' . $_guid);
|
||||
}
|
||||
}
|
||||
|
||||
// validate the meta data payload
|
||||
if (empty($_meta)) {
|
||||
$this->state = STATE_META_ERROR;
|
||||
$this->logger->data(ERROR_DATA_META_REQUIRED);
|
||||
$this->eventMessages[] = ERROR_DATA_META_REQUIRED;
|
||||
return;
|
||||
} elseif (!array_key_exists(META_TEMPLATE, $_meta)) {
|
||||
$this->state = STATE_META_ERROR;
|
||||
$msg = ERROR_DATA_META_KEY_404 . META_TEMPLATE;
|
||||
$this->logger->data($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
return;
|
||||
}
|
||||
|
||||
// invoke the parent constructor, load the mysql configuration
|
||||
parent::__construct();
|
||||
$this->status = false;
|
||||
$this->config = gasConfig::$settings[CONFIG_DATABASE_MYSQL];
|
||||
if (empty($this->config)) {
|
||||
$msg = ERROR_CONFIG_RESOURCE_404 . RESOURCE_MYSQL;
|
||||
$this->logger->warn($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->state = STATE_RESOURCE_ERROR_MYSQL;
|
||||
return;
|
||||
}
|
||||
|
||||
// load the template
|
||||
$this->templateName = STRING_CLASS_GAT . $_meta[META_TEMPLATE];
|
||||
if (!$this->loadTemplate()) {
|
||||
$this->logger->warn(ERROR_TEMPLATE_INSTANTIATE . $_meta[META_TEMPLATE]);
|
||||
$this->state = STATE_TEMPLATE_ERROR;
|
||||
return;
|
||||
}
|
||||
$this->class = $_meta[META_TEMPLATE]; // set the class to the name of the requested data class
|
||||
|
||||
// if we're passed an optional $_id, then evaluate which type of id we're working with and make
|
||||
// the appropriate assignments.
|
||||
if (!empty($_id)) {
|
||||
$_id = trim($_id);
|
||||
$_id = (is_numeric($_id)) ? abs(intval($_id)) : $_id;
|
||||
switch (gettype($_id)) {
|
||||
case DATA_TYPE_STRING :
|
||||
if (validateGUID($_id)) {
|
||||
if ($this->pKey != PKEY_GUID) {
|
||||
$msg = sprintf(ERROR_PKEY_TYPE, DATA_TYPE_STRING);
|
||||
$this->logger->error($msg);
|
||||
$this->state = STATE_DATA_TYPE_ERROR;
|
||||
$this->eventMessages[] = $msg;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$msg = ERROR_INVALID_GUID . $_id;
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->error($msg);
|
||||
$this->state = STATE_DATA_ERROR;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case DATA_TYPE_INTEGER :
|
||||
if ($this->pKey != PKEY_ID) {
|
||||
$msg = sprintf(ERROR_PKEY_TYPE, DATA_TYPE_INTEGER);
|
||||
$this->logger->error($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->state = STATE_DATA_TYPE_ERROR;
|
||||
return;
|
||||
}
|
||||
$this->pKey = PKEY_ID;
|
||||
break;
|
||||
default :
|
||||
$msg = sprintf(ERROR_PKEY_TYPE, gettype($_id));
|
||||
$this->logger->error($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->state = STATE_DATA_TYPE_ERROR;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// establish and assign mysql connections
|
||||
if (gasResourceManager::$mySqlMasterAvailable) {
|
||||
$this->connection = gasResourceManager::fetchResource(RESOURCE_MYSQL_MASTER);
|
||||
$this->mysqlMasterAvailable = true;
|
||||
if (gasResourceManager::$mySqlSlaveAvailable) {
|
||||
$this->slaveConnection = gasResourceManager::fetchResource(RESOURCE_MYSQL_SLAVE);
|
||||
$this->mysqlSlaveAvailable = true;
|
||||
} else {
|
||||
$this->mysqlSlaveAvailable = false;
|
||||
}
|
||||
} else {
|
||||
$this->mysqlMasterAvailable = false;
|
||||
$this->state = STATE_RESOURCE_ERROR_MYSQL;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->queryOrderBy = null;
|
||||
$this->queryGroupBy = null;
|
||||
$this->queryLimit = null;
|
||||
$this->queryHaving = null;
|
||||
$this->queryGroupByDirection = null;
|
||||
$this->queryGroupByDirection = null;
|
||||
$this->serviceReady = true;
|
||||
// if we have an $_id, load the record
|
||||
if ($this->collectionName != NONE) {
|
||||
$this->buildIndexReference();
|
||||
$this->setRowsReturnedLimit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* buildIndexReference() -- private method
|
||||
*
|
||||
* this method looks at the table defined in the current class instantiation and fetches the schema
|
||||
* information about the table from mysql.
|
||||
*
|
||||
* Each returned array structure from the query looks like this:
|
||||
*
|
||||
* Array
|
||||
* (
|
||||
* [Field] => email_usr
|
||||
* [Type] => varchar(50)
|
||||
* [Null] => NO
|
||||
* [Key] => UNI
|
||||
* [Default] =>
|
||||
* [Extra] =>
|
||||
* )
|
||||
*
|
||||
* We're looking for the column 'Key' to be not-empty as this indicates that the table column is indexed
|
||||
* in some way.
|
||||
*
|
||||
* We want to save the indexed column information in a K->V paired array so that, when we're parsing
|
||||
* queries submitted to the mysql service, we can screen the query and prevent the execution of any
|
||||
* query that does not use the indexed columns of the table.
|
||||
*
|
||||
* The K->V associative array will be stored locally in the the $fieldTypes variable (declared in the core).
|
||||
*
|
||||
* The Key will contain the name of the indexed column, and the Value will have the mysql type definition
|
||||
* for that column.
|
||||
*
|
||||
* If the query execution generates a mysql error, set a WARN message and return.
|
||||
* If the query executes, but no indexed columns are returned, raise a WARN message.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0.0
|
||||
*
|
||||
* HISTORY:
|
||||
* --------
|
||||
* 06-30-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function buildIndexReference()
|
||||
{
|
||||
if ($this->trace) $this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
|
||||
$data = null;
|
||||
// generate the cache key appropriate to the class and see if we've already cached this info
|
||||
// based off a previous instantiation...
|
||||
$cKey = CACHE_NAMASTE_KEY . '_' . CACHE_MYSQL_TABLE_SCHEMA . '_' . $this->collectionName;
|
||||
if ($data = gasCache::get($cKey)) {
|
||||
$data = json_decode(gzuncompress($data), true);
|
||||
} else {
|
||||
$this->dbEvent = DB_EVENT_NAMASTE;
|
||||
$this->strQuery = 'SHOW COLUMNS FROM ' . $this->collectionName;
|
||||
$this->executeNonPreparedQuery();
|
||||
if (!$this->rowsAffected) {
|
||||
$this->logger->warn(ERROR_SQL_FTL_INDEXES);
|
||||
$this->eventMessages[] = ERROR_SQL_FTL_INDEXES;
|
||||
} else {
|
||||
foreach($this->queryResults as $row) {
|
||||
$data[] = $row;
|
||||
}
|
||||
}
|
||||
gasCache::add($cKey, gzcompress(json_encode($data, true)));
|
||||
}
|
||||
if (!empty($data) and is_array($data)) {
|
||||
foreach ($data as $row) {
|
||||
@$this->mySqlTypes[$row[MYSQL_COLUMN_FIELD]] = $row[MYSQL_COLUMN_TYPE];
|
||||
if (!empty($row[MYSQL_COLUMN_KEY])) {
|
||||
$this->indexes[] = $row[MYSQL_COLUMN_FIELD];
|
||||
}
|
||||
if (@$row[MYSQL_COLUMN_KEY] == MYSQL_INDEX_PRIMARY or @$row[MYSQL_COLUMN_KEY] == MYSQL_INDEX_UNIQUE) {
|
||||
$this->uniqueIndexes[] = $row[MYSQL_COLUMN_FIELD];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* setRowsReturnedLimit() -- private method
|
||||
*
|
||||
* this function is called in the constructor for the current table instantiation.
|
||||
*
|
||||
* it looks at the information_schema table to get the average_row_length (arl) value for the table.
|
||||
* this is a gross calculation - the more data in the table, the more accurate the value.
|
||||
*
|
||||
* if we can get the arl value from the information_schema, then divide this number into the system
|
||||
* constant (max_data_returned) to see if the result is less-than or equal-to the system constant for the
|
||||
* number of rows returned per query...
|
||||
*
|
||||
* if the calculated value is smaller, then allow the system constants to remain -- if not, adjust the system
|
||||
* constant for the max_rows_returned so that the total amount of data remains under the system constant
|
||||
* max_data_returned.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* 07-10-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function setRowsReturnedLimit()
|
||||
{
|
||||
if (gasConfig::$settings[ERROR_TRACE] and $this->logger->available) {
|
||||
$this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
}
|
||||
$key = PDO_DATA_DEFINITION . '_' . PDO_AVG_ROW_LEN . '_' . $this->collectionName;
|
||||
$cacheData = null;
|
||||
$this->dbEvent = MYSQL_EVENT_META;
|
||||
|
||||
if ($cacheData = gasCache::get($key)) {
|
||||
$cacheData = json_decode(gzuncompress($cacheData), true);
|
||||
$this->recordLimit = $cacheData[PDO_RECORDS_PER_PAGE];
|
||||
} else {
|
||||
$schema = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MYSQL][CONFIG_DATABASE_MYSQL_APPSERVER][CONFIG_DATABASE_MYSQL_MASTER][CONFIG_DATABASE_MYSQL_DB];
|
||||
$this->strQuery = '-- noinspection SqlDialectInspection
|
||||
SELECT AVG_ROW_LENGTH
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = "' . $schema . '"
|
||||
AND table_name = "' . $this->collectionName . '"';
|
||||
$this->recordLimit = PDO_RECORDS_PER_PAGE;
|
||||
$this->executeNonPreparedQuery();
|
||||
if (($this->rowsAffected === 1) and (isset($this->queryResult[0][MYSQL_AVG_ROW_LENGTH]))) {
|
||||
$arl = $this->queryResult[0][MYSQL_AVG_ROW_LENGTH];
|
||||
if (($arl * PDO_RECORDS_PER_PAGE) > MYSQL_MAX_DATA_RETURNED) {
|
||||
$this->recordLimit = intval(MYSQL_MAX_DATA_RETURNED / $arl);
|
||||
}
|
||||
}
|
||||
$cacheData[PDO_RECORDS_PER_PAGE] = $this->recordLimit;
|
||||
if (!gasCache::add(PDO_DATA_DEFINITION . '_' . PDO_AVG_ROW_LEN . '_' . $this->collectionName, gzcompress(json_encode($cacheData, true)), gasCache::$cacheTTL)) {
|
||||
$this->logger->warn('memcache:set failed - check log files');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* executeNonPreparedQuery() -- private method
|
||||
*
|
||||
* this is the main method to execute all META and SELECT queries - any query that is not a prepared statement
|
||||
* will execute here. Basically, namaste queries.
|
||||
*
|
||||
* upon invocation, the string passed (implicitly through the member variable: $query) will be cleaned through
|
||||
* the common function, and then we'll evaluate the query based on the setting of the member variable $dbEvent.
|
||||
* If $dbEvent is not META and not SELECT, then we're going to return with a WARN message requiring the client
|
||||
* to use the prepared-query method.
|
||||
*
|
||||
* Next, parse the query and look for the "?" character - which is used as a place holder in prepared queries,
|
||||
* and, if found, reject the request and return with a WARN message.
|
||||
*
|
||||
* Call a private method to see if the slave server is enabled and, if so, use it if the current query contains
|
||||
* the SELECT keyword (meta queries will not use SELECT) and return the connection resource to a local variable.
|
||||
*
|
||||
* if query timers are enabled, then mark the start time and execute the query. record the end-time and log
|
||||
* the query through the parent::method().
|
||||
*
|
||||
* Make a call to fetch the data as an associative array and post the results, along with the row count, to
|
||||
* class variables.
|
||||
*
|
||||
* if the query generated an mysql error, generate an WARN message and return.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0.0
|
||||
*
|
||||
* HISTORY:
|
||||
* --------
|
||||
* 06-30-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function executeNonPreparedQuery()
|
||||
{
|
||||
if ($this->trace) $this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
|
||||
$startTime = floatval(0);
|
||||
|
||||
if ($this->debug) {
|
||||
$this->logger->debug($this->strQuery);
|
||||
}
|
||||
|
||||
// todo: can I exec this schema command using the read-slave? Do I want to?
|
||||
/** @var $dbLink mysqli() */
|
||||
$dbLink = $this->connection;
|
||||
|
||||
if ($this->useTimers) $startTime = floatval(0);
|
||||
$this->queryResults = null;
|
||||
if ($this->dbEvent != DB_EVENT_NAMASTE) {
|
||||
$this->strQuery = cleanQueryString($this->strQuery);
|
||||
}
|
||||
|
||||
switch($this->dbEvent) {
|
||||
case DB_EVENT_NAMASTE :
|
||||
case DB_EVENT_SELECT :
|
||||
break;
|
||||
default :
|
||||
$this->logger->error(ERROR_SQL_NOT_PREP_STMNT);
|
||||
return;
|
||||
}
|
||||
if (stripos($this->strQuery, '?')) {
|
||||
$this->logger->warn(ERROR_SQL_LOST_PREP_QUERY);
|
||||
$this->logger->warn($this->strQuery);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->useTimers) {
|
||||
$startTime = gasStatic::doingTime();
|
||||
}
|
||||
if ($result = $dbLink->query($this->strQuery)) {
|
||||
$this->rowsAffected = $result->num_rows;
|
||||
if ($this->useTimers) {
|
||||
$this->logger->metrics($this->strQuery, gasStatic::doingTime($startTime));
|
||||
$this->logger->debug(MYSQL_ROWS_AFFECTED . $this->rowsAffected);
|
||||
}
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$this->queryResult[] = $row;
|
||||
}
|
||||
} else {
|
||||
$this->logger->warn('error expecting query: ' . $this->strQuery);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* loadTemplate() -- private method
|
||||
*
|
||||
* this method is invoked by the constructor and serves to load the class template file, assimilating it into
|
||||
* the current instantiation.
|
||||
*
|
||||
* template loads are done on the schema-instantiation level, instead of the core, because of the changes in
|
||||
* the template file(s) across various schemas.
|
||||
*
|
||||
* the method will load the class template and set the class member variables controlled/referenced by the
|
||||
* template.
|
||||
*
|
||||
* successful loading of the template is determined by the return (boolean) value -- on error, a log message
|
||||
* will be generated so it's up to the developer to check logs on fail-returns to see why their template
|
||||
* file was not correctly assimilated.
|
||||
*
|
||||
* The template to be loaded is first derived in the constructor (post validation that the template file
|
||||
* exists) and is pulled from the member variable (also set in the constructor) within this method.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0.0
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-30-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function loadTemplate():bool
|
||||
{
|
||||
if ($this->trace) $this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
|
||||
try {
|
||||
/** @var gatTestMySQL template */
|
||||
$this->template = new $this->templateName;
|
||||
} catch (Exception $e) {
|
||||
$this->logger->warn($e->getMessage());
|
||||
$this->state = STATE_FRAMEWORK_FAIL;
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (!is_object($this->template)) {
|
||||
$this->logger->warn(ERROR_FILE_404 . $this->templateName);
|
||||
$this->setState(ERROR_FILE_404 . $this->templateName);
|
||||
return (false);
|
||||
}
|
||||
|
||||
if ($this->template->schema != TEMPLATE_DB_PDO) {
|
||||
$this->logger->warn(ERROR_SCHEMA_MISMATCH . $this->template->schema . ERROR_STUB_EXPECTING . TEMPLATE_DB_PDO);
|
||||
$this->setState(ERROR_SCHEMA_MISMATCH . $this->templateName);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// transfer meta data info to current instantiation
|
||||
$this->schema = $this->template->schema;
|
||||
$this->collectionName = $this->template->collection;
|
||||
$this->ext = $this->template->extension;
|
||||
$this->useCache = $this->template->setCache;
|
||||
$this->useDeletes = $this->template->setDeletes;
|
||||
$this->useAuditing = $this->template->setAuditing;
|
||||
$this->useJournaling = $this->template->setJournaling;
|
||||
$this->allowUpdates = $this->template->setUpdates;
|
||||
$this->useDetailedHistory = $this->template->setHistory;
|
||||
$this->defaultStatus = $this->template->setDefaultStatus;
|
||||
$this->searchStatus = $this->template->setSearchStatus;
|
||||
$this->useLocking = $this->template->setLocking;
|
||||
$this->useTimers = ($this->template->setTimers and gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_QUERY_TIMERS]);
|
||||
$this->pKey = $this->template->setPKey;
|
||||
$this->useToken = $this->template->setTokens;
|
||||
$this->cacheExpiry = $this->template->cacheTimer;
|
||||
|
||||
if (isset($this->template->fields) and is_array($this->template->fields)) {
|
||||
foreach ($this->template->fields as $key => $value) {
|
||||
if ($key == DB_HISTORY) {
|
||||
$this->fieldList[] = $key;
|
||||
$this->fieldTypes[$key] = $value;
|
||||
} else {
|
||||
$this->fieldList[] = ($key . $this->ext);
|
||||
$this->fieldTypes[($key . $this->ext)] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->template->indexes) and is_array($this->template->indexes)) {
|
||||
foreach ($this->template->indexes as $key => $value) {
|
||||
$this->indexes[] = ($key . $this->ext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!is_null($this->template->cacheMap) and $this->useCache) {
|
||||
foreach ($this->template->cacheMap as $key => $value) {
|
||||
$this->cacheMap[($key . $this->ext)] = $value;
|
||||
}
|
||||
} elseif (!$this->useCache) {
|
||||
$this->cacheMap = null;
|
||||
if (!is_null($this->template->exposedFields)) {
|
||||
$this->exposedFields = $this->template->exposedFields;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($this->template->uniqueIndexes)) $this->uniqueIndexes = $this->template->uniqueIndexes;
|
||||
|
||||
if (!is_null($this->template->compoundIndexes)) $this->compoundIndexes = $this->template->compoundIndexes;
|
||||
|
||||
if (!is_null($this->template->binFields)) {
|
||||
foreach ($this->template->binFields as $key) {
|
||||
$this->binaryFields[] = ($key . $this->ext);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->template->selfDestruct) {
|
||||
unset($this->template);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
protected function _createRecord($_data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _fetchRecords($_dd, $_rd = null, $_co = true, $_skip = 0, $_limit = 0, $_sort = null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _updateRecord($_data){
|
||||
|
||||
}
|
||||
|
||||
protected function _deleteRecord($_data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _lockRecord()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _releaseLock()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _isLocked()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* class destructor
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-29-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
//
|
||||
// destructor is registered shut-down function in constructor -- so any recovery
|
||||
// efforts should go in this method.
|
||||
|
||||
// there is no destructor method defined in the core abstraction class, hence
|
||||
// there is no call to that parent destructor in this class.
|
||||
parent::__destruct();
|
||||
}
|
||||
}
|
||||
709
classes/deprecated/gacMySQL.class.txt
Normal file
709
classes/deprecated/gacMySQL.class.txt
Normal file
@@ -0,0 +1,709 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BindParams -- helper class
|
||||
*
|
||||
* this is a helper class for the gacMySQL class, specifically for generating dynamic prepared statements.
|
||||
*
|
||||
* this class, when instantiated, creates storage for a prepared statement's type and values. When we want to
|
||||
* create the prepared statement, we use call_user_func_array() and use the output from this method to generate
|
||||
* the arguments that are normally passed in a prepared statement.
|
||||
*
|
||||
* using this class allows a data payload to be dynamically parsed and validated - allows a client to update
|
||||
* a sub-set of a table without having to explicitly enumerate every column in the table.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* --------
|
||||
* 06-29-17 mks original coding
|
||||
*
|
||||
*/
|
||||
class BindParams {
|
||||
private $values = array();
|
||||
private $types = '';
|
||||
|
||||
/**
|
||||
* add() -- public method
|
||||
*
|
||||
* this method accepts two parameters as input - the type of the variable and the value of the variable. In
|
||||
* this instance, when I say variable, I am referring to a mysql table column.
|
||||
*
|
||||
* if, for some unknown reason, type is a value not allowed, reset it to type 's' which should cover-up most
|
||||
* mistakes.
|
||||
*
|
||||
* $value as a call-by-reference to suppress a PHP warning message.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $type
|
||||
* @param $value
|
||||
*
|
||||
* HISTORY:
|
||||
* --------
|
||||
* 06-29-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function add(string $type, &$value)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'd' :
|
||||
case 'i' :
|
||||
case 'b' :
|
||||
case 's' :
|
||||
break;
|
||||
default :
|
||||
$type = 's';
|
||||
}
|
||||
$this->values[] = $value;
|
||||
$this->types .= $type;
|
||||
}
|
||||
|
||||
public function isEmpty()
|
||||
{
|
||||
return((empty($this->values)) ? true : false);
|
||||
}
|
||||
|
||||
public function checkOrd()
|
||||
{
|
||||
return((count($this->values) == strlen($this->types)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* get() -- public method
|
||||
*
|
||||
* get() simply returns the two class variables as a string of output that's tailored to the input
|
||||
* requirement of mysqli::bind_param().
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* HISTORY:
|
||||
* --------
|
||||
* 06-29-17 mks Original coding
|
||||
*
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
return array_merge(array($this->types), $this->values);
|
||||
}
|
||||
|
||||
public function refValues($arr) {
|
||||
$refs = array();
|
||||
foreach($arr as $key => $value)
|
||||
$refs[$key] = &$arr[$key];
|
||||
return $refs;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class gacMySQL extends gaaNamasteCore
|
||||
{
|
||||
private $slaveConnection = null; // resource link to mysqli service
|
||||
protected $useSlaveServer = false; // should be overridden in the class instantiation
|
||||
protected $batchSize = PDO_RECORDS_PER_PAGE;
|
||||
protected $mySqlTypes = array();
|
||||
protected $tip = false; // indicates if a transaction is already in progress
|
||||
protected $uniqueIndexes = null;
|
||||
protected $compoundIndexes = null;
|
||||
protected $exposedFields = null;
|
||||
protected $dbEvent; // used to track the different sql events
|
||||
protected $rowsAffected; // how many rows were affected by the sql query
|
||||
protected $queryResult; // container to hold return payload from mysqli
|
||||
protected $recordLimit;
|
||||
protected $serviceReady; // boolean indicating if the mysql service is ready
|
||||
|
||||
// exceptions to the query-builder
|
||||
public $queryOrderBy;
|
||||
public $queryOrderByDirection;
|
||||
public $queryGroupBy;
|
||||
public $queryGroupByDirection;
|
||||
public $queryLimit;
|
||||
public $queryHaving;
|
||||
public $mysqlMasterAvailable;
|
||||
public $mysqlSlaveAvailable;
|
||||
|
||||
// allowable operands for mysql
|
||||
public $operands = [
|
||||
OPERATOR_EQ,
|
||||
OPERATOR_LTE,
|
||||
OPERATOR_GTE,
|
||||
OPERATOR_DNE,
|
||||
OPERATOR_LT,
|
||||
OPERATOR_GT,
|
||||
OPERATOR_NE
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* __construct -- public method
|
||||
*
|
||||
* constructor for the mysql data instantiation class
|
||||
*
|
||||
* Three input parameters are supported for the constructor:
|
||||
*
|
||||
* $_template: the name of the template that establishes which data class will be instantiated
|
||||
* $_meta: the meta data payload as received from the broker - critical because it contains the name
|
||||
* of the class template we're going to be instantiating.
|
||||
* $_id: an optional parameter - if provided, we'll instantiate the class and then attempt to load
|
||||
* the record referenced by the primary key value (after evaluating the id type).
|
||||
*
|
||||
* Next, we going to assign mysql resources - based on the configuration, if we're supporting slave reads, make
|
||||
* the appropriate assignments so the correct resource is engaged for any particular query.
|
||||
*
|
||||
* Load the template properties into the class and set the class properties accordingly.
|
||||
*
|
||||
* Every mySQL table has two "primary keys" -- the traditional auto-incrementing integer, and a guid string.
|
||||
* The best-practices effort of "id's internally, guids externally" applies to mysql structures.
|
||||
*
|
||||
* When we instantiate the class and we receive an id, we have to evaluate if we're passed a string (guid) or an
|
||||
* integer (id) and adjust the current pkey pointer appropriately so that correct query is build deeper down.
|
||||
*
|
||||
* Therefore, mysql is the first and, of this writing, the only db instantiation class that has a floating pkey
|
||||
* value/type which is established on a data fetch at run-time.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_template
|
||||
* @param array $_meta
|
||||
* @param mixed $_id
|
||||
*
|
||||
* HISTORY:
|
||||
* --------
|
||||
* 06-29-17 mks initial coding
|
||||
*
|
||||
*/
|
||||
public function __construct(string $_template, array $_meta, $_id = null)
|
||||
{
|
||||
register_shutdown_function(array($this, '__destruct'));
|
||||
|
||||
parent::__construct();
|
||||
|
||||
if ($this->trace and $this->logger->available) {
|
||||
$this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
if (!empty($_guid) and $this->debug) {
|
||||
$this->logger->debug('received guid: ' . $_guid);
|
||||
}
|
||||
}
|
||||
|
||||
// validate the meta data payload
|
||||
if (empty($_meta)) {
|
||||
$this->state = STATE_META_ERROR;
|
||||
$this->logger->data(ERROR_DATA_META_REQUIRED);
|
||||
$this->eventMessages[] = ERROR_DATA_META_REQUIRED;
|
||||
return;
|
||||
} elseif (!array_key_exists(META_TEMPLATE, $_meta)) {
|
||||
$this->state = STATE_META_ERROR;
|
||||
$msg = ERROR_DATA_META_KEY_404 . META_TEMPLATE;
|
||||
$this->logger->data($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
return;
|
||||
}
|
||||
|
||||
// invoke the parent constructor, load the mysql configuration
|
||||
parent::__construct();
|
||||
$this->status = false;
|
||||
$this->config = gasConfig::$settings[CONFIG_DATABASE_MYSQL];
|
||||
if (empty($this->config)) {
|
||||
$msg = ERROR_CONFIG_RESOURCE_404 . RESOURCE_MYSQL;
|
||||
$this->logger->warn($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->state = STATE_RESOURCE_ERROR_MYSQL;
|
||||
return;
|
||||
}
|
||||
|
||||
// load the template
|
||||
$this->templateName = STRING_CLASS_GAT . $_meta[META_TEMPLATE];
|
||||
if (!$this->loadTemplate()) {
|
||||
$this->logger->warn(ERROR_TEMPLATE_INSTANTIATE . $_meta[META_TEMPLATE]);
|
||||
$this->state = STATE_TEMPLATE_ERROR;
|
||||
return;
|
||||
}
|
||||
$this->class = $_meta[META_TEMPLATE]; // set the class to the name of the requested data class
|
||||
|
||||
// if we're passed an optional $_id, then evaluate which type of id we're working with and make
|
||||
// the appropriate assignments.
|
||||
if (!empty($_id)) {
|
||||
$_id = trim($_id);
|
||||
$_id = (is_numeric($_id)) ? abs(intval($_id)) : $_id;
|
||||
switch (gettype($_id)) {
|
||||
case DATA_TYPE_STRING :
|
||||
if (validateGUID($_id)) {
|
||||
if ($this->pKey != PKEY_GUID) {
|
||||
$msg = sprintf(ERROR_PKEY_TYPE, DATA_TYPE_STRING);
|
||||
$this->logger->error($msg);
|
||||
$this->state = STATE_DATA_TYPE_ERROR;
|
||||
$this->eventMessages[] = $msg;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$msg = ERROR_INVALID_GUID . $_id;
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->error($msg);
|
||||
$this->state = STATE_DATA_ERROR;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case DATA_TYPE_INTEGER :
|
||||
if ($this->pKey != PKEY_ID) {
|
||||
$msg = sprintf(ERROR_PKEY_TYPE, DATA_TYPE_INTEGER);
|
||||
$this->logger->error($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->state = STATE_DATA_TYPE_ERROR;
|
||||
return;
|
||||
}
|
||||
$this->pKey = PKEY_ID;
|
||||
break;
|
||||
default :
|
||||
$msg = sprintf(ERROR_PKEY_TYPE, gettype($_id));
|
||||
$this->logger->error($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->state = STATE_DATA_TYPE_ERROR;
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// establish and assign mysql connections
|
||||
if (gasResourceManager::$mySqlMasterAvailable) {
|
||||
$this->connection = gasResourceManager::fetchResource(RESOURCE_MYSQL_MASTER);
|
||||
$this->mysqlMasterAvailable = true;
|
||||
if (gasResourceManager::$mySqlSlaveAvailable) {
|
||||
$this->slaveConnection = gasResourceManager::fetchResource(RESOURCE_MYSQL_SLAVE);
|
||||
$this->mysqlSlaveAvailable = true;
|
||||
} else {
|
||||
$this->mysqlSlaveAvailable = false;
|
||||
}
|
||||
} else {
|
||||
$this->mysqlMasterAvailable = false;
|
||||
$this->state = STATE_RESOURCE_ERROR_MYSQL;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->queryOrderBy = null;
|
||||
$this->queryGroupBy = null;
|
||||
$this->queryLimit = null;
|
||||
$this->queryHaving = null;
|
||||
$this->queryGroupByDirection = null;
|
||||
$this->queryGroupByDirection = null;
|
||||
$this->serviceReady = true;
|
||||
// if we have an $_id, load the record
|
||||
if ($this->collectionName != NONE) {
|
||||
$this->buildIndexReference();
|
||||
$this->setRowsReturnedLimit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* buildIndexReference() -- private method
|
||||
*
|
||||
* this method looks at the table defined in the current class instantiation and fetches the schema
|
||||
* information about the table from mysql.
|
||||
*
|
||||
* Each returned array structure from the query looks like this:
|
||||
*
|
||||
* Array
|
||||
* (
|
||||
* [Field] => email_usr
|
||||
* [Type] => varchar(50)
|
||||
* [Null] => NO
|
||||
* [Key] => UNI
|
||||
* [Default] =>
|
||||
* [Extra] =>
|
||||
* )
|
||||
*
|
||||
* We're looking for the column 'Key' to be not-empty as this indicates that the table column is indexed
|
||||
* in some way.
|
||||
*
|
||||
* We want to save the indexed column information in a K->V paired array so that, when we're parsing
|
||||
* queries submitted to the mysql service, we can screen the query and prevent the execution of any
|
||||
* query that does not use the indexed columns of the table.
|
||||
*
|
||||
* The K->V associative array will be stored locally in the the $fieldTypes variable (declared in the core).
|
||||
*
|
||||
* The Key will contain the name of the indexed column, and the Value will have the mysql type definition
|
||||
* for that column.
|
||||
*
|
||||
* If the query execution generates a mysql error, set a WARN message and return.
|
||||
* If the query executes, but no indexed columns are returned, raise a WARN message.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* --------
|
||||
* 06-30-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function buildIndexReference()
|
||||
{
|
||||
if ($this->trace) $this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
|
||||
$data = null;
|
||||
// generate the cache key appropriate to the class and see if we've already cached this info
|
||||
// based off a previous instantiation...
|
||||
$cKey = CACHE_NAMASTE_KEY . '_' . CACHE_MYSQL_TABLE_SCHEMA . '_' . $this->collectionName;
|
||||
if ($data = gasCache::get($cKey)) {
|
||||
$data = json_decode(gzuncompress($data), true);
|
||||
} else {
|
||||
$this->dbEvent = DB_EVENT_NAMASTE;
|
||||
$this->strQuery = 'SHOW COLUMNS FROM ' . $this->collectionName;
|
||||
$this->executeNonPreparedQuery();
|
||||
if (!$this->rowsAffected) {
|
||||
$this->logger->warn(ERROR_SQL_FTL_INDEXES);
|
||||
$this->eventMessages[] = ERROR_SQL_FTL_INDEXES;
|
||||
} else {
|
||||
foreach($this->queryResults as $row) {
|
||||
$data[] = $row;
|
||||
}
|
||||
}
|
||||
gasCache::add($cKey, gzcompress(json_encode($data, true)));
|
||||
}
|
||||
if (!empty($data) and is_array($data)) {
|
||||
foreach ($data as $row) {
|
||||
@$this->mySqlTypes[$row[MYSQL_COLUMN_FIELD]] = $row[MYSQL_COLUMN_TYPE];
|
||||
if (!empty($row[MYSQL_COLUMN_KEY])) {
|
||||
$this->indexes[] = $row[MYSQL_COLUMN_FIELD];
|
||||
}
|
||||
if (@$row[MYSQL_COLUMN_KEY] == MYSQL_INDEX_PRIMARY or @$row[MYSQL_COLUMN_KEY] == MYSQL_INDEX_UNIQUE) {
|
||||
$this->uniqueIndexes[] = $row[MYSQL_COLUMN_FIELD];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* setRowsReturnedLimit() -- private method
|
||||
*
|
||||
* this function is called in the constructor for the current table instantiation.
|
||||
*
|
||||
* it looks at the information_schema table to get the average_row_length (arl) value for the table.
|
||||
* this is a gross calculation - the more data in the table, the more accurate the value.
|
||||
*
|
||||
* if we can get the arl value from the information_schema, then divide this number into the system
|
||||
* constant (max_data_returned) to see if the result is less-than or equal-to the system constant for the
|
||||
* number of rows returned per query...
|
||||
*
|
||||
* if the calculated value is smaller, then allow the system constants to remain -- if not, adjust the system
|
||||
* constant for the max_rows_returned so that the total amount of data remains under the system constant
|
||||
* max_data_returned.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* 07-10-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function setRowsReturnedLimit()
|
||||
{
|
||||
if (gasConfig::$settings[ERROR_TRACE] and $this->logger->available) {
|
||||
$this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
}
|
||||
$key = PDO_DATA_DEFINITION . '_' . PDO_AVG_ROW_LEN . '_' . $this->collectionName;
|
||||
$cacheData = null;
|
||||
$this->dbEvent = MYSQL_EVENT_META;
|
||||
|
||||
if ($cacheData = gasCache::get($key)) {
|
||||
$cacheData = json_decode(gzuncompress($cacheData), true);
|
||||
$this->recordLimit = $cacheData[PDO_RECORDS_PER_PAGE];
|
||||
} else {
|
||||
$schema = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MYSQL][CONFIG_DATABASE_MYSQL_APPSERVER][CONFIG_DATABASE_MYSQL_MASTER][CONFIG_DATABASE_MYSQL_DB];
|
||||
$this->strQuery = '-- noinspection SqlDialectInspection
|
||||
SELECT AVG_ROW_LENGTH
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = "' . $schema . '"
|
||||
AND table_name = "' . $this->collectionName . '"';
|
||||
$this->recordLimit = PDO_RECORDS_PER_PAGE;
|
||||
$this->executeNonPreparedQuery();
|
||||
if (($this->rowsAffected === 1) and (isset($this->queryResult[0][MYSQL_AVG_ROW_LENGTH]))) {
|
||||
$arl = $this->queryResult[0][MYSQL_AVG_ROW_LENGTH];
|
||||
if (($arl * PDO_RECORDS_PER_PAGE) > MYSQL_MAX_DATA_RETURNED) {
|
||||
$this->recordLimit = intval(MYSQL_MAX_DATA_RETURNED / $arl);
|
||||
}
|
||||
}
|
||||
$cacheData[PDO_RECORDS_PER_PAGE] = $this->recordLimit;
|
||||
if (!gasCache::add(PDO_DATA_DEFINITION . '_' . PDO_AVG_ROW_LEN . '_' . $this->collectionName, gzcompress(json_encode($cacheData, true)), gasCache::$cacheTTL)) {
|
||||
$this->logger->warn('memcache:set failed - check log files');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* executeNonPreparedQuery() -- private method
|
||||
*
|
||||
* this is the main method to execute all META and SELECT queries - any query that is not a prepared statement
|
||||
* will execute here. Basically, namaste queries.
|
||||
*
|
||||
* upon invocation, the string passed (implicitly through the member variable: $query) will be cleaned through
|
||||
* the common function, and then we'll evaluate the query based on the setting of the member variable $dbEvent.
|
||||
* If $dbEvent is not META and not SELECT, then we're going to return with a WARN message requiring the client
|
||||
* to use the prepared-query method.
|
||||
*
|
||||
* Next, parse the query and look for the "?" character - which is used as a place holder in prepared queries,
|
||||
* and, if found, reject the request and return with a WARN message.
|
||||
*
|
||||
* Call a private method to see if the slave server is enabled and, if so, use it if the current query contains
|
||||
* the SELECT keyword (meta queries will not use SELECT) and return the connection resource to a local variable.
|
||||
*
|
||||
* if query timers are enabled, then mark the start time and execute the query. record the end-time and log
|
||||
* the query through the parent::method().
|
||||
*
|
||||
* Make a call to fetch the data as an associative array and post the results, along with the row count, to
|
||||
* class variables.
|
||||
*
|
||||
* if the query generated an mysql error, generate an WARN message and return.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* --------
|
||||
* 06-30-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function executeNonPreparedQuery()
|
||||
{
|
||||
if ($this->trace) $this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
|
||||
$startTime = floatval(0);
|
||||
|
||||
if ($this->debug) {
|
||||
$this->logger->debug($this->strQuery);
|
||||
}
|
||||
|
||||
// todo: can I exec this schema command using the read-slave? Do I want to?
|
||||
/** @var $dbLink mysqli() */
|
||||
$dbLink = $this->connection;
|
||||
|
||||
if ($this->useTimers) $startTime = floatval(0);
|
||||
$this->queryResults = null;
|
||||
if ($this->dbEvent != DB_EVENT_NAMASTE) {
|
||||
$this->strQuery = cleanQueryString($this->strQuery);
|
||||
}
|
||||
|
||||
switch($this->dbEvent) {
|
||||
case DB_EVENT_NAMASTE :
|
||||
case DB_EVENT_SELECT :
|
||||
break;
|
||||
default :
|
||||
$this->logger->error(ERROR_SQL_NOT_PREP_STMNT);
|
||||
return;
|
||||
}
|
||||
if (stripos($this->strQuery, '?')) {
|
||||
$this->logger->warn(ERROR_SQL_LOST_PREP_QUERY);
|
||||
$this->logger->warn($this->strQuery);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->useTimers) {
|
||||
$startTime = gasStatic::doingTime();
|
||||
}
|
||||
if ($result = $dbLink->query($this->strQuery)) {
|
||||
$this->rowsAffected = $result->num_rows;
|
||||
if ($this->useTimers) {
|
||||
$this->logger->metrics($this->strQuery, gasStatic::doingTime($startTime));
|
||||
$this->logger->debug(MYSQL_ROWS_AFFECTED . $this->rowsAffected);
|
||||
}
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$this->queryResult[] = $row;
|
||||
}
|
||||
} else {
|
||||
$this->logger->warn('error expecting query: ' . $this->strQuery);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* loadTemplate() -- private method
|
||||
*
|
||||
* this method is invoked by the constructor and serves to load the class template file, assimilating it into
|
||||
* the current instantiation.
|
||||
*
|
||||
* template loads are done on the schema-instantiation level, instead of the core, because of the changes in
|
||||
* the template file(s) across various schemas.
|
||||
*
|
||||
* the method will load the class template and set the class member variables controlled/referenced by the
|
||||
* template.
|
||||
*
|
||||
* successful loading of the template is determined by the return (boolean) value -- on error, a log message
|
||||
* will be generated so it's up to the developer to check logs on fail-returns to see why their template
|
||||
* file was not correctly assimilated.
|
||||
*
|
||||
* The template to be loaded is first derived in the constructor (post validation that the template file
|
||||
* exists) and is pulled from the member variable (also set in the constructor) within this method.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-30-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function loadTemplate():bool
|
||||
{
|
||||
if ($this->trace) $this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
|
||||
try {
|
||||
/** @var gatTestMySQL template */
|
||||
$this->template = new $this->templateName;
|
||||
} catch (Exception $e) {
|
||||
$this->logger->warn($e->getMessage());
|
||||
$this->state = STATE_FRAMEWORK_FAIL;
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (!is_object($this->template)) {
|
||||
$this->logger->warn(ERROR_FILE_404 . $this->templateName);
|
||||
$this->setState(ERROR_FILE_404 . $this->templateName);
|
||||
return (false);
|
||||
}
|
||||
|
||||
if ($this->template->schema != TEMPLATE_DB_PDO) {
|
||||
$this->logger->warn(ERROR_SCHEMA_MISMATCH . $this->template->schema . ERROR_STUB_EXPECTING . TEMPLATE_DB_PDO);
|
||||
$this->setState(ERROR_SCHEMA_MISMATCH . $this->templateName);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// transfer meta data info to current instantiation
|
||||
$this->schema = $this->template->schema;
|
||||
$this->collectionName = $this->template->collection;
|
||||
$this->ext = $this->template->extension;
|
||||
$this->useCache = $this->template->setCache;
|
||||
$this->useDeletes = $this->template->setDeletes;
|
||||
$this->useAuditing = $this->template->setAuditing;
|
||||
$this->useJournaling = $this->template->setJournaling;
|
||||
$this->allowUpdates = $this->template->setUpdates;
|
||||
$this->useDetailedHistory = $this->template->setHistory;
|
||||
$this->defaultStatus = $this->template->setDefaultStatus;
|
||||
$this->searchStatus = $this->template->setSearchStatus;
|
||||
$this->useLocking = $this->template->setLocking;
|
||||
$this->useTimers = ($this->template->setTimers and gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_QUERY_TIMERS]);
|
||||
$this->pKey = $this->template->setPKey;
|
||||
$this->useToken = $this->template->setTokens;
|
||||
$this->cacheExpiry = $this->template->cacheTimer;
|
||||
|
||||
if (isset($this->template->fields) and is_array($this->template->fields)) {
|
||||
foreach ($this->template->fields as $key => $value) {
|
||||
if ($key == DB_HISTORY) {
|
||||
$this->fieldList[] = $key;
|
||||
$this->fieldTypes[$key] = $value;
|
||||
} else {
|
||||
$this->fieldList[] = ($key . $this->ext);
|
||||
$this->fieldTypes[($key . $this->ext)] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->template->indexes) and is_array($this->template->indexes)) {
|
||||
foreach ($this->template->indexes as $key => $value) {
|
||||
$this->indexes[] = ($key . $this->ext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!is_null($this->template->cacheMap) and $this->useCache) {
|
||||
foreach ($this->template->cacheMap as $key => $value) {
|
||||
$this->cacheMap[($key . $this->ext)] = $value;
|
||||
}
|
||||
} elseif (!$this->useCache) {
|
||||
$this->cacheMap = null;
|
||||
if (!is_null($this->template->exposedFields)) {
|
||||
$this->exposedFields = $this->template->exposedFields;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($this->template->uniqueIndexes)) $this->uniqueIndexes = $this->template->uniqueIndexes;
|
||||
|
||||
if (!is_null($this->template->compoundIndexes)) $this->compoundIndexes = $this->template->compoundIndexes;
|
||||
|
||||
if (!is_null($this->template->binFields)) {
|
||||
foreach ($this->template->binFields as $key) {
|
||||
$this->binaryFields[] = ($key . $this->ext);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->template->selfDestruct) {
|
||||
unset($this->template);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
protected function _createRecord($_data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _fetchRecords($_dd, $_rd = null, $_co = true, $_skip = 0, $_limit = 0, $_sort = null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _updateRecord($_data){
|
||||
|
||||
}
|
||||
|
||||
protected function _deleteRecord($_data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _lockRecord()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _releaseLock()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _isLocked()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* class destructor
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-29-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
//
|
||||
// destructor is registered shut-down function in constructor -- so any recovery
|
||||
// efforts should go in this method.
|
||||
|
||||
// there is no destructor method defined in the core abstraction class, hence
|
||||
// there is no call to that parent destructor in this class.
|
||||
parent::__destruct();
|
||||
}
|
||||
}
|
||||
193
classes/deprecated/gacPDO.class.txt
Normal file
193
classes/deprecated/gacPDO.class.txt
Normal file
@@ -0,0 +1,193 @@
|
||||
/**
|
||||
* cacheByTokenList() -- private method
|
||||
*
|
||||
* This method requires a single input parameter -- that's an array of tokens in the following format:
|
||||
*
|
||||
* array (
|
||||
* 0 =>
|
||||
* array (
|
||||
* 'token_tst' => '2DB9636A-C14D-F2C9-7CDA-E7808C1EA600',
|
||||
* ),
|
||||
* )
|
||||
*
|
||||
* This method is used from the update event -- when we've already completed the update successfully and the
|
||||
* current class has been populated with the successful update-query results, which we wish to preserve.
|
||||
*
|
||||
* The updated records, represented by the token list, has to be re-cached. So this method is going to exec
|
||||
* a SELECT query to fetch the updated records for caching. This is a prepared query.
|
||||
*
|
||||
* Since we don't want to overwrite the results of the update query in the current class object, we're going to
|
||||
* clone the object, execute the select query from that object, and transfer the results over to the original
|
||||
* class before releasing the cloned object.
|
||||
*
|
||||
* Prior to said release, we're going to call the method to process the data members and cache the records and,
|
||||
* on return, transfer the cache keys (if caching is enabled for the class) or the data.
|
||||
*
|
||||
* The method returns a boolean indicating success or failure for all of the operation.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_tList
|
||||
* @return bool
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-31-17 mks CORE-586: original coding
|
||||
*
|
||||
*/
|
||||
private function cacheByTokenList(array $_tList): bool
|
||||
{
|
||||
if (!is_array($_tList)) {
|
||||
$this->eventMessages[] = ERROR_DATA_ARRAY_NOT_ARRAY . STRING_TOKEN;
|
||||
return false;
|
||||
}
|
||||
// clone the current object so we don't overwrite any of the current class members & zero-out the important bits
|
||||
$tObj = clone $this;
|
||||
$tObj->queryVariables = null;
|
||||
$tObj->strQuery = '';
|
||||
$tObj->queryResults = '';
|
||||
$tObj->count = 0;
|
||||
$tObj->dbEvent = DB_EVENT_SELECT;
|
||||
|
||||
/*
|
||||
* build the query to fetch the record based on the token list which looks like:
|
||||
*
|
||||
* array (
|
||||
* 0 =>
|
||||
* array (
|
||||
* 'token_xxx' => '2DB9636A-C14D-F2C9-7CDA-E7808C1EA600',
|
||||
* ),
|
||||
* )
|
||||
*/
|
||||
$query = 'SELECT /* ' . basename(__FILE__) . COLON . __METHOD__ . AT . __LINE__ . ' */ ';
|
||||
$query .= '* FROM ';
|
||||
if (!isset($tObj->template->dbObjects[PDO_VIEWS][PDO_VIEW_BASIC . $tObj->collectionName])) {
|
||||
$query .= $tObj->collectionName;
|
||||
} else {
|
||||
$query .= PDO_VIEW_BASIC . $tObj->collectionName;
|
||||
}
|
||||
$query .= ' ';
|
||||
$query .= 'WHERE ' . STRING_TOKEN . $tObj->ext . ' IN (';
|
||||
foreach ($_tList as $record) {
|
||||
$query .= '?, ';
|
||||
$tObj->queryVariables[] = $record[(STRING_TOKEN . $tObj->ext)];
|
||||
}
|
||||
$query = rtrim($query, ', ');
|
||||
$query .= ') ';
|
||||
if (!$tObj->useDeletes) {
|
||||
$query .= 'AND status' . $tObj->ext . ' != ?';
|
||||
$tObj->queryVariables[] = STATUS_DELETED;
|
||||
}
|
||||
$tObj->strQuery = $query;
|
||||
|
||||
try {
|
||||
$tObj->executePreparedQuery();
|
||||
if (!$tObj->status) {
|
||||
$this->eventMessages = array_merge($this->eventMessages, $tObj->eventMessages);
|
||||
return false;
|
||||
}
|
||||
|
||||
$tObj->data = $tObj->queryResults;
|
||||
if (!$tObj->returnFilteredData()) {
|
||||
$this->eventMessages = array_merge($this->eventMessages, $tObj->eventMessages);
|
||||
$this->eventMessages[] = ERROR_RFD_CORE_FAIL;
|
||||
return false;
|
||||
}
|
||||
} catch (Throwable $t) {
|
||||
$msg = ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
$this->eventMessages[] = $msg;
|
||||
if (isset($this->logger) and $this->logger->available)
|
||||
$this->logger->error($msg);
|
||||
else
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
$this->state = STATE_FRAMEWORK_WARNING;
|
||||
return false;
|
||||
}
|
||||
// copy data from the clone to the original
|
||||
$this->eventMessages = array_merge($this->eventMessages, $tObj->eventMessages);
|
||||
$this->cacheKeys = $tObj->cacheKeys;
|
||||
$this->data = $tObj->data;
|
||||
$tObj->__destruct();
|
||||
unset($tObj);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getCacheTokenListQuery() -- private method
|
||||
*
|
||||
* This method is called from the update and delete methods for when we need to generate a list of affected tokens
|
||||
* for these operations. We need to generate this list b/c the operation will modify the records and, if the
|
||||
* records exist in cache, they should be removed.
|
||||
*
|
||||
* The method requires one input parameter which is the list of tokens we're going to build as a result of the
|
||||
* query. As such, all of the query elements must have been built prior to invoking this method as those member
|
||||
* elements are used to build this SELECT query...
|
||||
*
|
||||
* We'll execute the prepared select query and store the results in an array which is implicitly returned to the
|
||||
* calling client.
|
||||
*
|
||||
* The method proper returns a boolean to indicate success or fail in processing as a null value returned for
|
||||
* the token list is permissible.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array|null $_tokenList
|
||||
* @return boolean
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-26-17 mks CORE-586: original coding
|
||||
*
|
||||
*/
|
||||
private function getCacheTokenListQuery(array &$_tokenList = null): bool
|
||||
{
|
||||
$rc = false;
|
||||
|
||||
$cq = 'SELECT /* ' . basename(__FILE__) . COLON . __METHOD__ . AT . __LINE__ . ' */ ';
|
||||
$cq .= DB_TOKEN . $this->ext . ' ';
|
||||
$cq .= 'FROM ' . $this->collectionName . ' ';
|
||||
$cq .= 'WHERE ' . $this->where . ' ';
|
||||
if (!is_null($this->queryOrderBy)) {
|
||||
$cq .= 'ORDER BY ' . $this->queryOrderBy . ' ';
|
||||
}
|
||||
if (!is_null($this->queryLimit)) {
|
||||
$cq .= 'LIMIT ' . $this->queryLimit;
|
||||
}
|
||||
try {
|
||||
$this->dbEvent = DB_EVENT_NAMASTE_READ;
|
||||
$this->strQuery = $cq;
|
||||
$this->executePreparedQuery();
|
||||
if ($this->status) {
|
||||
$_tokenList = $this->queryResults;
|
||||
// foreach ($this->queryResults as $key ) {
|
||||
// $_tokenList[] = $key;
|
||||
// }
|
||||
if (empty($_tokenList)) $_tokenList = null;
|
||||
$rc = true;
|
||||
} else {
|
||||
$this->eventMessages[] = ERROR_PDO_CQ_QUERY;
|
||||
$this->state = STATE_DB_ERROR;
|
||||
}
|
||||
return $rc;
|
||||
} catch (Throwable $t) {
|
||||
$msg = sprintf(ERROR_EXCEPTION . COLON . $this->strQuery[0]);
|
||||
consoleLog(RES_PDO, CON_ERROR, $msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->eventMessages[] = $t->getMessage();
|
||||
if (isset($this->logger) and $this->logger->available) {
|
||||
$this->logger->warn($msg);
|
||||
$this->logger->warn($t->getMessage());
|
||||
} else {
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
consoleLog($this->res, CON_ERROR, $t->getMessage());
|
||||
}
|
||||
$this->status = false;
|
||||
$this->state = STATE_DB_ERROR;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
204
classes/deprecated/gasCache.class.txt
Normal file
204
classes/deprecated/gasCache.class.txt
Normal file
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* convertCacheMap() -- private static method
|
||||
*
|
||||
* This private method is the gateway/entry-point for cacheMapping on data payloads. The function has the following
|
||||
* required input parameters:
|
||||
*
|
||||
* $_data -- this is the payload to be cacheMapped. This should be an indexed array of one, or more, assoc arrays
|
||||
* $_dir -- string value indicating if the data is incoming (IN) or outbound (OUT)
|
||||
* $_map -- this is the class-specific vector of cacheMapped settings pulled from the global cacheMap
|
||||
* $_type -- this defines the data payload as either record-data or query-data
|
||||
* $_errs -- this is a call-by-reference array that allows us to propagate error messages back up the stack
|
||||
*
|
||||
* The function looks at the contents of most of the input parameters and validates the content returning a null
|
||||
* if any of the params fail validation while also adding messages to the error stack and by publishing a message
|
||||
* to the error logger.
|
||||
*
|
||||
* Once validation is complete, we pass all of the input params to a second private function, allowing for
|
||||
* recursion in that function, and hopefully get back an array (which is passed though back up to the calling
|
||||
* client) that is successfully cacheMapped.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_data
|
||||
* @param string $_dir
|
||||
* @param array $_map
|
||||
* @param string $_type
|
||||
* @param array $_errs
|
||||
* @return array|null
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-25-19 mks DB-116: original coding
|
||||
*
|
||||
*/
|
||||
private static function convertCacheMap(array $_data, string $_dir, array $_map, string $_type, array &$_errs): ?array
|
||||
{
|
||||
// validate input param content -- input param type is implicitly validated by strong type decls
|
||||
if ($_dir != IN and $_dir != OUT) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
$msg = sprintf(ERROR_CACHE_DIRECTION, (string) $_dir);
|
||||
$_errs[] = $msg;
|
||||
static::$logger->data($hdr . $msg);
|
||||
return null;
|
||||
}
|
||||
if ($_type != STRING_QUERY and $_type != STRING_DATA) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
$msg = ERROR_CACHE_MAP_TYPE . $_type;
|
||||
$_errs[] = $msg;
|
||||
static::$logger->error($hdr . $msg);
|
||||
return null;
|
||||
}
|
||||
if (!is_array($_data)) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
$msg = $hdr . ERROR_DATA_ARRAY_NOT_ARRAY . STRING_DATA;
|
||||
$_errs[] = $msg;
|
||||
static::$logger->data($msg);
|
||||
return null;
|
||||
}
|
||||
if (!is_array($_map)) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
$msg = $hdr . ERROR_DATA_ARRAY_NOT_ARRAY . CACHE_MAP;
|
||||
$_errs[] = $msg;
|
||||
static::$logger->data($msg);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return static::processCacheMap($_data, $_map, $_dir, $_type, $_errs);
|
||||
} catch (TypeError $t) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
$msg = $hdr . ERROR_TYPE_EXCEPTION;
|
||||
$_errs[] = $msg;
|
||||
static::$logger->warn($msg);
|
||||
$msg = $hdr . $t->getMessage();
|
||||
$_errs[] = $msg;
|
||||
static::$logger->warn($msg);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* processCacheMap() -- private static method with recursion
|
||||
*
|
||||
* This function is responsible for the cacheMapping for both incoming and outbound data payloads. It is a
|
||||
* stand-alone function because of it's recursive nature -- when we encounter a sub-array within the payload,
|
||||
* we must recursively call this method in order to process the sub-array (etc.).
|
||||
*
|
||||
* There are the following input parameters to this method, all of which are required:
|
||||
*
|
||||
* $_data -- this is the incoming/outgoing data payload. The invoking method has parsed, for example, the incoming
|
||||
* data payload and, as an example, let's say there are three sub-arrays stored in the payload:
|
||||
* STRING_QUERY_DATA, STRING_SORT_DATA and STRING_RETURN_DATA -- the invoking method will make a total of three
|
||||
* calls to this method, one for each of the sub-arrays under BROKER_DATA. Note that $_data should be passed as
|
||||
* an indexed array s.t. each tuple in the array is processed as a separate record.
|
||||
*
|
||||
* $_map -- this is the cacheMap for the targeted class. In other words, it is not the entire cacheMap but the
|
||||
* named tuple for the current data class.
|
||||
*
|
||||
* $_dir -- this is a string value that may only be either IN or OUT (both are Namaste system constants). IN
|
||||
* designates the payload as incoming while OUT designates the payload as outbound.
|
||||
*
|
||||
* $_type -- this is a string value, defined as either STRING_QUERY or STRING_DATA, and is verified in the
|
||||
* the calling client. This value designates the type of payload to be mapped.
|
||||
*
|
||||
* $_es -- this is an array for the error-stack -- it's a call-by-reference parameter s.t. we can propagate any
|
||||
* error messages back to the invoking client.
|
||||
*
|
||||
* The method returns an array which, under optimal conditions, returns a mirror of the incoming data payload
|
||||
* save that the keys have been successfully cacheMapped.
|
||||
*
|
||||
* Any filed which fails cacheMapping (e.g.: not found) will be stored in the class static $badCacheFields and
|
||||
* will be implicitly returned to the calling client for processing.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* @param array $_data -- indexed array of data to be cacheMapped; may contain more than one record
|
||||
* @param array $_map -- cacheMap for the current data class
|
||||
* @param string $_dir -- indicates the direction (flow) of the data: either INcoming or OUTbound
|
||||
* @param string $_type - indicates payload type: either DATA or QUERY (validated in calling client)
|
||||
* @param array $_es -- call-by-reference array for returning error messages to the calling client
|
||||
* @return array|null -- returns the cacheMapped array or a null on error
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-25-19 mks DB-116: original coding
|
||||
*
|
||||
*/
|
||||
private static function processCacheMap(array $_data, array $_map, string $_dir, string $_type, array &$_es): ?array
|
||||
{
|
||||
$data = null; // container to hold the cacheMapped record
|
||||
$records = null; // container to hold all the cacheMapped records
|
||||
// todo -- test for subCollection array existing in the subC setting... which means you have to add it to the cacheMap data
|
||||
// this is where the cache-mapping magic happens...
|
||||
foreach ($_data as $record => $recordData) {
|
||||
foreach ($record as $column => &$value) {
|
||||
if ($_dir == IN) { // todo -- map off the type...
|
||||
// we're cache-mapping an incoming payload
|
||||
if (in_array($column, $_map[CACHE_MAP])) {
|
||||
if (is_array($value) and $_map[CACHE_SUBC] != STRING_NOT_DEFINED and array_key_exists(array_search($column, $_map[CACHE_MAP]), $_map[CACHE_SUBC])) {
|
||||
// note: not checking for the case where $value is an array but $newKey is not defined in the
|
||||
// cached SUBC definition for the class. This loose definition for sub-collections
|
||||
// permits the user to store sub-arrays without inspection/validation/mapping.
|
||||
try {
|
||||
// we have to process $value recursively as a sub-array
|
||||
$data[array_search($column, $_map[CACHE_MAP])] = static::processCacheMap($value, $_map, $_dir, $_type, $_es);
|
||||
} catch (TypeError $t) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
$msg = $hdr . ERROR_TYPE_EXCEPTION;
|
||||
$_errs[] = $msg;
|
||||
static::$logger->warn($msg);
|
||||
$msg = $hdr . $t->getMessage();
|
||||
$_errs[] = $msg;
|
||||
static::$logger->warn($msg);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
$data[array_search($column, $_map[CACHE_MAP])] = $value;
|
||||
}
|
||||
} else {
|
||||
static::$badCacheFields[$column] = $value;
|
||||
}
|
||||
} else {
|
||||
// we're cache-mapping an outbound payload so remove the class extension from the column name
|
||||
$newKey = str_replace($_map[CACHE_EXT], '', $column);
|
||||
if (array_key_exists($newKey, $_map[CACHE_MAP])) {
|
||||
// note: not checking for the case where $value is an array but $newKey is not defined in the
|
||||
// cached SUBC definition for the class. This loose definition for sub-collections
|
||||
// permits the user to store sub-arrays without inspection/validation/mapping.
|
||||
if (is_array($value) and $_map[CACHE_SUBC] != STRING_NOT_DEFINED and array_key_exists($newKey, $_map[CACHE_SUBC])) {
|
||||
try {
|
||||
// we have to process $value recursively as a sub-array
|
||||
$data[$_map[CACHE_MAP][$newKey]] = static::processCacheMap($value, $_map, $_dir, $_type,$_es);
|
||||
} catch (TypeError $t) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
$msg = $hdr . ERROR_TYPE_EXCEPTION;
|
||||
$_errs[] = $msg;
|
||||
static::$logger->warn($msg);
|
||||
$msg = $hdr . $t->getMessage();
|
||||
$_errs[] = $msg;
|
||||
static::$logger->warn($msg);
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
$data[$_map[CACHE_MAP][$newKey]] = $value;
|
||||
}
|
||||
} else {
|
||||
static::$badCacheFields[$newKey] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($data)) {
|
||||
$records[] = $data;
|
||||
unset($data);
|
||||
} // todo: else?
|
||||
return $records;
|
||||
}
|
||||
3388
classes/gaaNamasteCore.class.inc
Normal file
3388
classes/gaaNamasteCore.class.inc
Normal file
File diff suppressed because it is too large
Load Diff
366
classes/gacATWrapper.class.inc
Normal file
366
classes/gacATWrapper.class.inc
Normal file
@@ -0,0 +1,366 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This is a wrapper class for the AT daemon. It was plagiarized from:
|
||||
*
|
||||
* https://github.com/treffynnon/PHP-at-Job-Queue-Wrapper/blob/master/lib/Treffynnon/At/Wrapper.php
|
||||
*
|
||||
* Because the original (author's) version uses exceptions for error reporting. I've re-tooled the original code,
|
||||
* eliminating the exception processing, making the output logging align with Namaste's logging formats, and closing
|
||||
* access publicly to all methods except the intended public function.
|
||||
*
|
||||
* @author treffynnon@php.net Simon Holywell
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks port from original source
|
||||
* 08-17-20 mks DB-168: code review
|
||||
*
|
||||
*/
|
||||
class gacATWrapper
|
||||
{
|
||||
protected static string $binary = 'at'; // path to the AT binary
|
||||
protected static string $addRegex = '/^job (\d+) at ([\w\d- :]+)$/'; // regexp to fetch the current job listings
|
||||
protected static array $addMap = array( // regexp mapping -> descriptive names
|
||||
1 => 'job_number',
|
||||
2 => 'date',
|
||||
);
|
||||
// regexp for fetching queue info
|
||||
protected static string $queueRegex = '/^(\d+)\s+([\w\d- :]+) (\w) ([\w-]+)$/';
|
||||
// another regexp matching for queue data
|
||||
protected static array $queueMap = array(
|
||||
1 => 'job_number',
|
||||
2 => 'date',
|
||||
3 => 'queue',
|
||||
4 => 'user',
|
||||
);
|
||||
|
||||
protected static string $res = 'CRON: ';
|
||||
protected static string $pipeTo = '2>&1'; // redirects STDERR to STDOUT (redundant)
|
||||
|
||||
protected static array $atSwitches = array( // supported AT options list
|
||||
'queue' => '-q',
|
||||
'list_queue' => '-l',
|
||||
'file' => '-f',
|
||||
'remove' => '-d',
|
||||
);
|
||||
|
||||
/**
|
||||
* cmd() -- public static function
|
||||
*
|
||||
* @users self::addCommand
|
||||
*
|
||||
* @param $command
|
||||
* @param $time
|
||||
* @param null $queue
|
||||
* @return mixed
|
||||
*/
|
||||
static public function cmd($command, $time, $queue = null)
|
||||
{
|
||||
return self::addCommand($command, $time, $queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @uses self::addFile
|
||||
*
|
||||
* @param $file
|
||||
* @param $time
|
||||
* @param null $queue
|
||||
* @return mixed
|
||||
*/
|
||||
static public function file($file, $time, $queue = null)
|
||||
{
|
||||
return self::addFile($file, $time, $queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @uses self::listQueue
|
||||
*
|
||||
* @param null $queue
|
||||
* @return mixed
|
||||
*/
|
||||
static public function lq($queue = null)
|
||||
{
|
||||
return self::listQueue($queue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a job to the `at` queue
|
||||
* @param string $command
|
||||
* @param string $time see `man at`
|
||||
* @param string $queue a-zA-Z see `man at`
|
||||
* @return mixed
|
||||
*/
|
||||
static private function addCommand($command, $time, $queue = null)
|
||||
{
|
||||
$command = self::escape($command);
|
||||
$time = self::escape($time);
|
||||
$exec_string = "echo '$command' | " . self::$binary;
|
||||
if(null !== $queue) {
|
||||
$exec_string .= ' ' . self::$atSwitches['queue'] . " {$queue[0]}";
|
||||
}
|
||||
$exec_string .= " $time ";
|
||||
return self::addJob($exec_string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a file job to the `at` queue
|
||||
* @param string $file Full path to the file to be executed
|
||||
* @param string $time see `man at`
|
||||
* @param string $queue a-zA-Z see `man at`
|
||||
* @return mixed
|
||||
*/
|
||||
static private function addFile($file, $time, $queue = null)
|
||||
{
|
||||
$file = self::escape($file);
|
||||
$time = self::escape($time);
|
||||
$exec_string = self::$binary . ' ' . self::$atSwitches['file'] . " $file";
|
||||
if(null !== $queue) {
|
||||
$exec_string .= ' ' . self::$atSwitches['queue'] . " {$queue[0]}";
|
||||
}
|
||||
$exec_string .= " $time ";
|
||||
return self::addJob($exec_string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a list of the jobs currently in the queue. If you do not specify
|
||||
* a queue to look at then it will return all jobs in all queues.
|
||||
* @param string $queue
|
||||
* @return array of Job objects
|
||||
* @return mixed
|
||||
*/
|
||||
static private function listQueue($queue = null)
|
||||
{
|
||||
$exec_string = self::$binary . ' ' . self::$atSwitches['list_queue'];
|
||||
if(null !== $queue) {
|
||||
$exec_string .= ' ' . self::$atSwitches['queue'] . " {$queue[0]}";
|
||||
}
|
||||
$result = self::exec($exec_string);
|
||||
return self::transform($result, 'queue');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a job by job number
|
||||
* @param int $job_number
|
||||
* @return Boolean
|
||||
*/
|
||||
static public function removeJob($job_number)
|
||||
{
|
||||
$rc = true;
|
||||
if (empty($job_number)) {
|
||||
$hdr = sprintf(INFO_LOC, __METHOD__, __LINE__);
|
||||
consoleLog(static::$res, CON_ERROR, $hdr . RES_ATW . ERROR_DATA_INPUT_EMPTY . STRING_JOB_NUMBER);
|
||||
return(false);
|
||||
}
|
||||
$job_number = self::escape($job_number);
|
||||
// $exec_string = self::$binary . ' ' . self::$atSwitches['remove'] . " $job_number";
|
||||
$exec_string = 'atrm ' . $job_number;
|
||||
$output = self::exec($exec_string);
|
||||
if(count($output)) {
|
||||
$rc = false;
|
||||
foreach ($output as $errorMessage) {
|
||||
$hdr = sprintf(INFO_LOC, __METHOD__, __LINE__);
|
||||
consoleLog(static::$res, CON_ERROR, $hdr . $errorMessage);
|
||||
}
|
||||
echo getDateTime() . CON_ERROR . RES_ATW . $output[0] . PHP_EOL;
|
||||
}
|
||||
return($rc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a job to the at queue and return the
|
||||
* @param string $job_exec_string
|
||||
* @return mixed
|
||||
*/
|
||||
static private function addJob($job_exec_string)
|
||||
{
|
||||
$output = self::exec($job_exec_string);
|
||||
return (count($output) == 1) ? $output[0] : $output[1];
|
||||
// $job = self::transform($output);
|
||||
// if(!count($job)) {
|
||||
// $logger = new gacErrorLogger();
|
||||
// $logger->warn('failed to add job to the queue. Exec command: ' . $job_exec_string);
|
||||
// $logger->__destruct();
|
||||
// }
|
||||
// return reset($job);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transform the output of `at` into an array of objects
|
||||
* @param array $output_array
|
||||
* @param string $type Is this an add or list we are transforming?
|
||||
* @return array An array of Job objects
|
||||
*/
|
||||
static private function transform(array $output_array, string $type = 'add'):array
|
||||
{
|
||||
$jobs = array();
|
||||
// Get the appropriate regex class property for the type
|
||||
// of `at` switch/command being run at this point in time.
|
||||
$regex = $type . 'Regex';
|
||||
$regex = self::$$regex;
|
||||
$map = $type .'Map';
|
||||
$map = self::$$map;
|
||||
|
||||
foreach($output_array as $line) {
|
||||
$matches = array();
|
||||
@preg_match($regex, $line, $matches);
|
||||
if(count($matches) > count($map)) {
|
||||
$jobs[] = self::mapJob($matches, $map);
|
||||
}
|
||||
}
|
||||
return $jobs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Map the details matched with the regex to descriptively named properties
|
||||
* in a new Job object
|
||||
* @param array $details
|
||||
* @param array $map
|
||||
* @return Job
|
||||
*/
|
||||
static private function mapJob($details, $map)
|
||||
{
|
||||
$Job = new Job();
|
||||
foreach($details as $key => $detail) {
|
||||
if(isset($map[$key])) {
|
||||
$Job->$map[$key] = $detail;
|
||||
}
|
||||
}
|
||||
return $Job;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Escape a string that will be passed to exec
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
static private function escape($string)
|
||||
{
|
||||
return escapeshellcmd($string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the command via exec() and return each line of the output as an
|
||||
* array
|
||||
* @param string $string
|
||||
* @return array Each line of output is an element in the array
|
||||
*/
|
||||
static private function exec($string)
|
||||
{
|
||||
$output = array();
|
||||
$string .= ' ' . self::$pipeTo;
|
||||
exec($string, $output);
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A simple class for storing a jobs details and some methods for manipulating
|
||||
* it. A job model if you will.
|
||||
*
|
||||
* @author Simon Holywell <treffynnon@php.net>
|
||||
* @version 16.11.2010
|
||||
*/
|
||||
class Job {
|
||||
/**
|
||||
* Data store for the job details
|
||||
* @var array
|
||||
*/
|
||||
public array $data = array();
|
||||
protected string $res = 'CRON: ';
|
||||
protected /** @noinspection PhpMissingFieldTypeInspection */ $date;
|
||||
|
||||
/**
|
||||
* Magic method to set a value in the $data
|
||||
* property of the class
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
{
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Magic method to get a value in the $data property
|
||||
* of the class
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
if (isset($this->data[$name])) {
|
||||
return $this->data[$name];
|
||||
}
|
||||
$logger = new gacErrorLogger();
|
||||
$trace = debug_backtrace();
|
||||
$logger->warn("Undefined property via __get(): $name in $trace[0]['file'] . on line $trace[0]['line']");
|
||||
$logger->__destruct();
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Magic method to check for the existence of an
|
||||
* index in the $data property of the class
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name)
|
||||
{
|
||||
return isset($this->data[$name]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Magic method to unset an index in the $data property
|
||||
* of the class
|
||||
* @param string $name
|
||||
*/
|
||||
public function __unset($name)
|
||||
{
|
||||
unset($this->data[$name]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove this job from the queue
|
||||
*/
|
||||
public function remove() {
|
||||
if(isset($this->job_number)) {
|
||||
gacATWrapper::removeJob((int)$this->job_number);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a DateTime object for date and time extracted from
|
||||
* the output of `at`
|
||||
* @example echo $job->date()->format('d-m-Y');
|
||||
* @uses DateTime
|
||||
* @return DateTime A PHP DateTime object
|
||||
*/
|
||||
public function date(): ?DateTime
|
||||
{
|
||||
try {
|
||||
return new DateTime($this->date);
|
||||
} catch (Exception | TypeError $t) {
|
||||
$hdr = sprintf(INFO_LOC, __METHOD__, __LINE__);
|
||||
consoleLog($this->res, CON_ERROR, $hdr . $t->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
253
classes/gacBrokerClient.class.inc
Normal file
253
classes/gacBrokerClient.class.inc
Normal file
@@ -0,0 +1,253 @@
|
||||
<?php
|
||||
/**
|
||||
* gacBrokerClient -- class definition
|
||||
*
|
||||
* this is the class for declaring a brokerClient for use in testing, or within the framework when we need to publish
|
||||
* an event to another queue (that's not a logging event).
|
||||
*
|
||||
* This class simply abstracts the RabbitMQ processes so that you don't have to re-write all the RMQ code every
|
||||
* time you want to publish a message to the queues.
|
||||
*
|
||||
* IMPORTANT NOTE:
|
||||
* ---------------
|
||||
* Whenever you add a new queue to the pantheon, you'll need to update the constructor class, adding the queue name
|
||||
* to the $validQueues member, and to the switch-case statement that assigns the correct environment.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks original coding
|
||||
* 02-08-17 mks _INF-139: updated for migrations broker, PHPDoc variable casting for AMQP members
|
||||
* 07-31-18 mks CORE-774: PHP7.2 exception handling
|
||||
* 09-18-19 mks DB-136: improved error messaging and exception handling
|
||||
*
|
||||
*/
|
||||
|
||||
//use PhpAmqpLib\Connection\AMQPStreamConnection;
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Exception\AMQPRuntimeException;
|
||||
use PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
|
||||
|
||||
class gacBrokerClient {
|
||||
private ?object $rabbitConnection = null;
|
||||
private ?AMQPChannel $rabbitChannel = null;
|
||||
private string $rabbitCallbackQueue;
|
||||
private ?string $rabbitResponse;
|
||||
private string $rabbitCorrelationID;
|
||||
private string $queueName;
|
||||
private array $validQueues;
|
||||
private gacErrorLogger $logger;
|
||||
private string $res = 'CLBR: ';
|
||||
public bool $status;
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* the constructor instantiates the class and establishes a connection to the RMQ broker.
|
||||
*
|
||||
* the constructor takes one input parameter:
|
||||
*
|
||||
* - queueName -- which queue does this instantiation wish to connect to
|
||||
*
|
||||
* as of this writing, there are two queuing services supported: namaste and admin. If more are added, then
|
||||
* they'll need to be defined (as constants) and the resource evaluation code updated.
|
||||
*
|
||||
* method returns a boolean indicating whether or not the resource management was successful and attempts to
|
||||
* provide diagnostics via logging, cli output, or via the status member variable.
|
||||
*
|
||||
* queue_declare arguments:
|
||||
* ------------------------
|
||||
* Queue Name: this is an arbitrary name, will be used to identify the queue
|
||||
* Passive: if set to true, the server will only check if the queue can be created, false will actually attempt to create the queue.
|
||||
* Durable: Typically, if the server stops or crashes, all queues and messages are lost... unless we declare the queue durable, in which case the queue will persist if the server is restarted.
|
||||
* Exclusive: If true, the queue can only be used by the connection that created it.
|
||||
* Autodelete: if true, the queue will be deleted once it has no messages and there are no subscribers connected
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $_queueName
|
||||
* @param $_tag
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks initial coding
|
||||
* 02-08-18 mks _INF-139: support for the migration broker, fixed return statements, console log
|
||||
* 04-11-18 mks _INF-188: warehousing broker support
|
||||
* 01-29-20 mks DB-144: tercero support
|
||||
* 12-10-20 mks DB-180: segundo cons broker support
|
||||
*
|
||||
*/
|
||||
public function __construct(string $_queueName, $_tag = 'default')
|
||||
{
|
||||
register_shutdown_function(array($this, '__destruct'));
|
||||
$this->status = false;
|
||||
try {
|
||||
$this->logger = new gacErrorLogger();
|
||||
} catch (TypeError $t) {
|
||||
consoleLog($this->res, CON_ERROR, ERROR_TYPE_EXCEPTION . $t->getMessage());
|
||||
}
|
||||
$this->queueName = $_queueName;
|
||||
$this->validQueues = [
|
||||
BROKER_QUEUE_R,
|
||||
BROKER_QUEUE_W,
|
||||
BROKER_QUEUE_AI,
|
||||
BROKER_QUEUE_AO,
|
||||
BROKER_QUEUE_M,
|
||||
BROKER_QUEUE_WH,
|
||||
BROKER_QUEUE_U,
|
||||
BROKER_QUEUE_S,
|
||||
BROKER_QUEUE_C
|
||||
];
|
||||
if (!in_array($this->queueName, $this->validQueues)) {
|
||||
$this->logger->warn(ERROR_INVALID_QUEUE_NAME . $this->queueName);
|
||||
} else {
|
||||
switch ($this->queueName) {
|
||||
case BROKER_QUEUE_R :
|
||||
case BROKER_QUEUE_W :
|
||||
case BROKER_QUEUE_M :
|
||||
$resource = RESOURCE_BROKER;
|
||||
break;
|
||||
|
||||
case BROKER_QUEUE_AI :
|
||||
case BROKER_QUEUE_AO :
|
||||
$resource = RESOURCE_ADMIN;
|
||||
break;
|
||||
|
||||
case BROKER_QUEUE_WH :
|
||||
case BROKER_QUEUE_C :
|
||||
$resource = RESOURCE_SEGUNDO;
|
||||
break;
|
||||
|
||||
case BROKER_QUEUE_U :
|
||||
case BROKER_QUEUE_S :
|
||||
$resource = RESOURCE_TERCERO;
|
||||
break;
|
||||
|
||||
default :
|
||||
$msg = ERROR_RESOURCE_404 . $_queueName;
|
||||
$this->logger->info($msg);
|
||||
consoleLog($this->res, CON_SYSTEM, $msg);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
try {
|
||||
$this->rabbitConnection = gasResourceManager::fetchResource($resource);
|
||||
if (is_null($this->rabbitConnection)) return;
|
||||
$this->rabbitChannel = $this->rabbitConnection->channel();
|
||||
$label = uniqid('gacBrokerClient<' . $_tag . '>:');
|
||||
list($this->rabbitCallbackQueue, ,) = $this->rabbitChannel->queue_declare($label, false, false, false, true); // was: f, f, f, t
|
||||
$this->rabbitChannel->basic_consume($this->rabbitCallbackQueue, '', false, false, false, false, array($this, BROKER_CLIENT_RESPONSE));
|
||||
$this->status = true;
|
||||
} catch (AMQPRuntimeException | AMQPTimeoutException | Throwable $t) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
consoleLog($this->res, CON_ERROR, $hdr . ERROR_THROWABLE_EXCEPTION);
|
||||
consoleLog($this->res, CON_ERROR, $hdr . $t->getMessage());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @noinspection PhpUnused
|
||||
* client_response -- public method
|
||||
*
|
||||
* this method checks to see if the current response, based on the correlation (request) ID, is the one it's
|
||||
* waiting for from the remote (vault) service.
|
||||
*
|
||||
* When it receives the awaited response, it stores the response into a member variable and exits.
|
||||
*
|
||||
*
|
||||
* @author mikegivingassistant.org
|
||||
* @version 1.0
|
||||
* @param $_response - the class object created in the constructor
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks original coding
|
||||
* 09-18-19 mks DB-136: exception wrapped this code
|
||||
*
|
||||
*/
|
||||
public function client_response(AMQPMessage $_response)
|
||||
{
|
||||
try {
|
||||
if ($_response->get(BROKER_CORRELATION_ID) == $this->rabbitCorrelationID) {
|
||||
$this->rabbitResponse = $_response->body;
|
||||
}
|
||||
} catch (AMQPTimeoutException | AMQPRuntimeException | Throwable $t) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
consoleLog($this->res, CON_ERROR, $hdr . ERROR_EXCEPTION);
|
||||
consoleLog($this->res, CON_ERROR, $hdr . $t->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* call() -- public method
|
||||
*
|
||||
* This method is invoked outside of the class and is the entry point for publishing a message request to the
|
||||
* broker. It creates a new AMQP message and publishes it to the queue (defined in the constructor), and then
|
||||
* blocks-and-waits for a response from the remote (vault) service.
|
||||
*
|
||||
* Publishing a message is exception trapped and will generate a log message at the warn level if tripped.
|
||||
*
|
||||
* The "raw" response is returned directly to the calling client and will be processed at that level.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $_data
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks original coding
|
||||
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
||||
*
|
||||
*/
|
||||
public function call($_data)
|
||||
{
|
||||
$this->rabbitResponse = null;
|
||||
$this->rabbitCorrelationID = uniqid();
|
||||
|
||||
$rabbitMessage = new AMQPMessage((string)$_data, [BROKER_CORRELATION_ID => $this->rabbitCorrelationID, BROKER_REPLY_TO => $this->rabbitCallbackQueue]);
|
||||
try {
|
||||
$this->rabbitChannel->basic_publish($rabbitMessage, '', (gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG] . $this->queueName));
|
||||
while (!$this->rabbitResponse) {
|
||||
$this->rabbitChannel->wait();
|
||||
}
|
||||
} catch (AMQPTimeoutException | AMQPRuntimeException | Throwable $e) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
$this->logger->fatal($hdr . ERROR_BROKER_EXCEPTION_TIMEOUT);
|
||||
$this->logger->fatal($hdr . $e->getMessage());
|
||||
consoleLog('_BTC: ', CON_ERROR, $hdr . $e->getMessage());
|
||||
}
|
||||
return ($this->rabbitResponse);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
// As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
//
|
||||
// destructor is registered shut-down function in constructor -- so any recovery
|
||||
// efforts should go in this method.
|
||||
try {
|
||||
if (!is_null($this->rabbitChannel))
|
||||
$this->rabbitChannel->close();
|
||||
if (!is_null($this->rabbitConnection))
|
||||
$this->rabbitConnection->close();
|
||||
} catch (Throwable $t) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
consoleLog($this->res, CON_ERROR, $hdr . ERROR_THROWABLE_EXCEPTION);
|
||||
consoleLog($this->res, CON_ERROR, $hdr. $t->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
354
classes/gacBrokerHelper.class.inc
Normal file
354
classes/gacBrokerHelper.class.inc
Normal file
@@ -0,0 +1,354 @@
|
||||
<?php
|
||||
/**
|
||||
* Class gacBrokerHelper
|
||||
*
|
||||
* There are certain events that are duplicated across the different services. These events, at the broker levels, had
|
||||
* their processing code/logic pulled and moved to this helper class.
|
||||
*
|
||||
* BrokerHelper is a vector for eliminating redundant code across the broker services.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-17-20 mks DB-156: original coding
|
||||
*
|
||||
*/
|
||||
|
||||
class gacBrokerHelper
|
||||
{
|
||||
private int $queryRecordLimit;
|
||||
private string $res = 'BH : ';
|
||||
public bool $status;
|
||||
public string $state;
|
||||
private ?gacErrorLogger $logger;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->logger = new gacErrorLogger();
|
||||
$this->queryRecordLimit = intval(gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_QUERY_RECORD_LIMIT]);
|
||||
$this->state = STATE_INITIALIZED;
|
||||
$this->status = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* create() -- public method
|
||||
*
|
||||
* This method was taken from the write-broker's create event. This method handles the class method invocations
|
||||
* for creating a new class record. There are three input parameters to this method:
|
||||
*
|
||||
* $_request -- this is the broker request containing all three parts (event, data and meta-data)
|
||||
* $_aryRetData -- call-by-reference object which is a broker's return payload array
|
||||
* $_msg -- call-by-reference string which is the generated console message
|
||||
*
|
||||
* This method calculates the query record limit (one of the XML configurable parameters) and returns immediately
|
||||
* if the number of submitted records exceeds the XML-stated limitation.
|
||||
*
|
||||
* Next, we instantiate a factory object based on the current meta-data payload and we'll return immediately if we
|
||||
* were unable to instantiate a factory class successfully.
|
||||
*
|
||||
* We copy off the widget (data class object) and invoke the create() method. On successful return, we cache-map
|
||||
* the outbound payload and build the aryRetData container based on those results.
|
||||
*
|
||||
* The method returns a boolean indicating whether or not the record(s) were successfully created.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_request
|
||||
* @param array|null $_aryRetData
|
||||
* @param string $_msg
|
||||
* @return bool|null
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-17-20 mks DB-156: original coding completed
|
||||
*
|
||||
*/
|
||||
public function create(array $_request, ?array &$_aryRetData, string &$_msg):?bool
|
||||
{
|
||||
$rc = false;
|
||||
$errors = [];
|
||||
if (count($_request[BROKER_DATA]) > $this->queryRecordLimit) {
|
||||
$_msg = ERROR_RECORD_LIMIT_EXCEEDED . $this->queryRecordLimit;
|
||||
$this->logger->error($_msg);
|
||||
$_aryRetData = buildReturnPayload([false, STATE_DATA_ERROR, $_msg, null]);
|
||||
return $rc;
|
||||
}
|
||||
try {
|
||||
/** @var gacMongoDB $widget */
|
||||
if (is_null($widget = grabWidget($_request[BROKER_META_DATA], '', $errors))) {
|
||||
foreach ($errors as $error)
|
||||
$this->logger->error($error);
|
||||
$_aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, ERROR_FACTORY_LOAD_BROKER . BROKER_REQUEST_CREATE, null]);
|
||||
return $rc;
|
||||
}
|
||||
$widget->_createRecord($_request[BROKER_DATA]);
|
||||
if ($widget->status) {
|
||||
if (gasCache::mapOutboundPayload($widget, $errors)) {
|
||||
$_aryRetData = buildReturnPayload([true, STATE_SUCCESS, $widget->queryResults, $widget->getCK()]);
|
||||
$rc = true;
|
||||
} else {
|
||||
$_aryRetData = buildReturnPayload([false, $widget->state, $widget->eventMessages, null]);
|
||||
$_msg = ERROR_CACHE_MAP_FAIL . ' tercero payload';
|
||||
$this->logger->warn($_msg);
|
||||
consoleLog($this->res, CON_ERROR, $_msg);
|
||||
}
|
||||
} else {
|
||||
$widget->eventMessages[] = FAIL_EVENT . BROKER_REQUEST_CREATE;
|
||||
$_aryRetData = buildReturnPayload([FALSE, $widget->state, $widget->eventMessages, null]);
|
||||
}
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
} catch (TypeError | Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $errors, true);
|
||||
$_aryRetData = buildReturnPayload([false, STATE_FAIL, ERROR_EXCEPTION, null]);
|
||||
}
|
||||
return $rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fetch() -- public function
|
||||
*
|
||||
* The fetch method was culled from the read broker event processing for the same event. It allows us to access
|
||||
* the fetch code from either the appServer or Tercero brokers.
|
||||
*
|
||||
* There are three input parameters to this method:
|
||||
*
|
||||
* $_request -- this is the array of event data submitted (Request, Data, Meta)
|
||||
* $_aryRetData -- call-by-reference parameter which is the array returned to the calling client
|
||||
* $_msg -- call by reference parameter that carries the console log message back to the calling client
|
||||
*
|
||||
* The method returns a boolean variable indicating if the fetch completed successfully or not. The data returned
|
||||
* in the fetch operation is implicitly returned via the method's input parameters.
|
||||
*
|
||||
* The method instantiates a factory object which builds the schema-widget which is then used to execute
|
||||
* the request query to fetch the data - the results of which are bundled-up and returned back to the
|
||||
* calling client.
|
||||
*
|
||||
* In this implementation, I've removed support for the remoteFetchRequest() method call because validateMetaData()
|
||||
* is now handling the tercero re-directs.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* @param array $_request
|
||||
* @param array|null $_aryRetData
|
||||
* @param string|null $_msg
|
||||
* @return bool
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-03-20 mks DB-157: original coding completed
|
||||
*
|
||||
*/
|
||||
public function fetch(array $_request, ?array &$_aryRetData = null, ?string &$_msg = null):bool
|
||||
{
|
||||
$errors = array();
|
||||
$rc = false;
|
||||
try {
|
||||
// cant instantiate remote-service objects in production, so we'll inject an skip
|
||||
// directive for the env-check... todo -- qualify this!
|
||||
/** @var gacMongoDB $objClass */
|
||||
if (is_null($objClass = grabWidget($_request[BROKER_META_DATA], '', $errors))) {
|
||||
foreach ($errors as $error)
|
||||
$this->logger->error($error);
|
||||
$_aryRetData = buildReturnPayload([false, STATE_DATA_ERROR, ERROR_FACTORY_LOAD_BROKER . BROKER_REQUEST_CREATE, null]);
|
||||
} else {
|
||||
// CORE-1013 ---------------------------------------------------------------
|
||||
$objClass->_fetchRecords($_request[BROKER_DATA]);
|
||||
if ($objClass->status) {
|
||||
$rc = true;
|
||||
$_msg = SUCCESS_EVENT . BROKER_REQUEST_FETCH;
|
||||
$queryMeta = [
|
||||
STRING_REC_COUNT_RET => $objClass->recordsReturned,
|
||||
STRING_REC_COUNT_QUERY => $objClass->recordsInQuery,
|
||||
STRING_REC_COUNT_TOT => $objClass->recordsInCollection
|
||||
];
|
||||
if ($objClass->state == STATE_NOT_FOUND and $objClass->count == 0) {
|
||||
$retData = [STRING_QUERY_RESULTS => null, STRING_QUERY_DATA => $queryMeta];
|
||||
} else {
|
||||
// cacheMapping call
|
||||
if (!gasCache::mapOutboundPayload($objClass, $errors)) {
|
||||
$queryResults = $objClass->getData();
|
||||
} else {
|
||||
// cache mapping succeeded - return the cache key
|
||||
$queryResults = $objClass->getCK();
|
||||
}
|
||||
$retData = [STRING_QUERY_RESULTS => $queryResults, STRING_QUERY_DATA => $queryMeta];
|
||||
}
|
||||
$_aryRetData = buildReturnPayload([true, $objClass->state, $objClass->eventMessages, $retData]);
|
||||
} else {
|
||||
$_msg = FAIL_EVENT . BROKER_REQUEST_FETCH;
|
||||
$_aryRetData = buildReturnPayload([false, $objClass->state, $objClass->eventMessages, null]);
|
||||
}
|
||||
if (is_object($objClass)) $objClass->__destruct();
|
||||
unset($objClass);
|
||||
}
|
||||
} catch (Throwable | TypeError $t) {
|
||||
$hdr = sprintf(basename(__METHOD__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $errors, true);
|
||||
$_aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, ERROR_EXCEPTION, null]);
|
||||
}
|
||||
return $rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* update() -- public function
|
||||
*
|
||||
* This function was populated using code from the write-broker update event. The code was moved to the BH class
|
||||
* so that it could be accessed by either the appServer:wBroker or tercero:userBroker brokers to process an
|
||||
* update request.
|
||||
*
|
||||
* The function requires three input parameters:
|
||||
*
|
||||
* $_request -- this is the request payload as received by the broker, post-validation processing
|
||||
* $_aryRetData -- this is a call-by-reference parameter that will contain the return payload that is sent back
|
||||
* to the calling client on completion
|
||||
* $_msg -- this is a string, a call-by-reference parameter, that will contain the event message for the
|
||||
* console log.
|
||||
*
|
||||
* The method itself returns a boolean value to indicate if processing successfully completed or not.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_request
|
||||
* @param array|null $_aryRetData
|
||||
* @param string|null $_msg
|
||||
* @return bool
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-04-20 mks DB-157: original coding happy birthday dad!
|
||||
*
|
||||
*/
|
||||
public function update(array $_request, ?array &$_aryRetData = null, ?string &$_msg = null):bool
|
||||
{
|
||||
$rc = false;
|
||||
$errors = [];
|
||||
|
||||
$objEvent = new gacFactory($_request[BROKER_META_DATA], FACTORY_EVENT_NEW_CLASS, '', $errors);
|
||||
if (!$objEvent->status) {
|
||||
$msg = ERROR_FACTORY_LOAD_BROKER . BROKER_REQUEST_CREATE;
|
||||
$_msg = $msg;
|
||||
$errors[] = $msg;
|
||||
$_aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, $errors, null]);
|
||||
$this->logger->fatal($msg);
|
||||
} else {
|
||||
/** @var gacMongoDB | gacPDO $objClass */
|
||||
$objClass = $objEvent->widget;
|
||||
if ($objClass->schema == TEMPLATE_DB_MONGO) {
|
||||
if (isset($request[BROKER_META_DATA][META_LIMIT]) and $_request[BROKER_META_DATA][META_LIMIT] !== 1)
|
||||
$request[BROKER_DATA][STRING_QUERY_OPTIONS][STRING_MULTI] = true;
|
||||
else
|
||||
$request[BROKER_DATA][STRING_QUERY_OPTIONS][STRING_MULTI] = false;
|
||||
}
|
||||
$objClass->_updateRecord($_request[BROKER_DATA]);
|
||||
if ($objClass->status) {
|
||||
$rc = true;
|
||||
$_msg = SUCCESS_EVENT . BROKER_REQUEST_UPDATE;
|
||||
try {
|
||||
if ($objClass->state == STATE_NOT_FOUND) {
|
||||
$_aryRetData = buildReturnPayload([false, STATE_NOT_FOUND, $objClass->eventMessages, null]);
|
||||
} else {
|
||||
$queryResults = (!gasCache::mapOutboundPayload($objClass, $errors)) ? $objClass->getData() : $objClass->getCK();
|
||||
$_aryRetData = buildReturnPayload([true, STATE_SUCCESS, $objClass->queryResults, $queryResults]);
|
||||
}
|
||||
} catch (TypeError | Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __FILE__);
|
||||
$msg = ERROR_EXCEPTION;
|
||||
$this->logger->error($hdr . $msg);
|
||||
$this->logger->error($t->getMessage());
|
||||
$_aryRetData = buildReturnPayload([false, STATE_FAIL, $msg, null]);
|
||||
$_msg = FAIL_EVENT . $hdr . $t->getMessage();
|
||||
}
|
||||
} else {
|
||||
$_msg = FAIL_EVENT . BROKER_REQUEST_UPDATE;
|
||||
$_aryRetData = buildReturnPayload([false, $objClass->state, $objClass->eventMessages, null]);
|
||||
}
|
||||
if (is_object($objClass)) $objClass->__destruct();
|
||||
unset($objClass);
|
||||
}
|
||||
if (is_object($objEvent)) $objEvent->__destruct();
|
||||
unset($objEvent);
|
||||
return $rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* delete() -- public method
|
||||
*
|
||||
* This method is the delete block formerly located in the write-broker, moved to the broker helper so that the
|
||||
* code is equally accessible by either appServer:wBroker or tercero:uBroker brokers.
|
||||
*
|
||||
* There are three input parameters to this method:
|
||||
*
|
||||
* $_request -- this is an array containing the processed data payload from the broker event request
|
||||
* $_aryRetData -- call-by-reference array that will contain the return payload to be sent back to the client
|
||||
* $_msg -- call-by-reference string that will contain the console log message from processing
|
||||
*
|
||||
* The method returns a boolean indicating if the routine successfully processed to completion or not.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_request
|
||||
* @param array|null $_aryRetData
|
||||
* @param string|null $_msg
|
||||
* @return bool
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-05-20 mks DB-157: original coding completed
|
||||
*
|
||||
*/
|
||||
public function delete(array $_request, ?array &$_aryRetData = null, ?string &$_msg = null): bool
|
||||
{
|
||||
$rc = false;
|
||||
$errors = [];
|
||||
|
||||
try {
|
||||
/** @var gacMongoDB $objClass */
|
||||
if (is_null($objClass = grabWidget($_request[BROKER_META_DATA], '', $errors))) {
|
||||
foreach ($errors as $error)
|
||||
$this->logger->error($error);
|
||||
$_aryRetData = buildReturnPayload([false, STATE_FRAMEWORK_FAIL, ERROR_FACTORY_LOAD_BROKER . BROKER_REQUEST_CREATE, null]);
|
||||
} else {
|
||||
$objClass->_deleteRecord($_request[BROKER_DATA]);
|
||||
if ($objClass->status and $objClass->state != STATE_NOT_FOUND) {
|
||||
$_msg = SUCCESS_EVENT . BROKER_REQUEST_DELETE;
|
||||
$rc = true;
|
||||
$_aryRetData = buildReturnPayload([true, STATE_SUCCESS, $objClass->eventMessages, [STRING_RECS_DELETED => $objClass->rowsAffected]]);
|
||||
} elseif ($objClass->status and $objClass->state == STATE_NOT_FOUND) {
|
||||
$_msg = FAIL_EVENT . BROKER_REQUEST_DELETE;
|
||||
$_aryRetData = buildReturnPayload([true, STATE_NOT_FOUND, $objClass->eventMessages, null]);
|
||||
} else {
|
||||
$_msg = FAIL_EVENT . BROKER_REQUEST_DELETE;
|
||||
$_aryRetData = buildReturnPayload([false, $objClass->state, $objClass->eventMessages, null]);
|
||||
}
|
||||
if (is_object($objClass)) $objClass->__destruct();
|
||||
unset($objClass);
|
||||
}
|
||||
} catch (Throwable | TypeError $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __FILE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $errors, true);
|
||||
$_aryRetData = buildReturnPayload([false, STATE_FAIL, ERROR_EXCEPTION, null]);
|
||||
}
|
||||
return $rc;
|
||||
}
|
||||
}
|
||||
498
classes/gacDdb.class.inc
Normal file
498
classes/gacDdb.class.inc
Normal file
@@ -0,0 +1,498 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* some assumptions to make:
|
||||
*
|
||||
* -- that this class will be invoked via the gacFactory class
|
||||
* -- that the gacFactory class will pre-validate the data template as being for the Ddb schema
|
||||
*
|
||||
*/
|
||||
class gacDdb extends gaaNamasteCore
|
||||
{
|
||||
private $globalIndexes = null;
|
||||
private $localIndexes = null;
|
||||
protected $service; // defines the end-point service
|
||||
|
||||
|
||||
/**
|
||||
* gacDdb constructor.
|
||||
*
|
||||
* the constructor for this class requires two input parameters:
|
||||
*
|
||||
* $_meta -- the meta data payload (has been vetted by the factory class)
|
||||
* $_guid -- an optional string containing a guid value -- if this is specified, then we're telling the class
|
||||
* to instantiate the class with the designated record pre-loaded.
|
||||
*
|
||||
* We're going to initialize with some housekeeping chores - like loading up the configuration, initializing
|
||||
* a connection to the DDB resource via the resource manager, and then loading the template.
|
||||
*
|
||||
* if we passed a guid into the method, validate the guid
|
||||
* if cache is enabled, check to see if the record is cached and, if so, load it
|
||||
* if the $data property is still null, call the method to load the record
|
||||
* note that the state/status of the class will be set here
|
||||
*
|
||||
* return control to the calling client
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_meta
|
||||
* @param string $_guid
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-21-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __construct(array $_meta, string $_guid = '')
|
||||
{
|
||||
// set-up
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
$this->status = false;
|
||||
|
||||
parent::__construct();
|
||||
|
||||
// load config
|
||||
$this->config = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_DDB];
|
||||
if (empty($this->config)) {
|
||||
$this->logger->fatal(ERROR_CONFIG_RESOURCE_404 . CONFIG_DATABASE . COLON . CONFIG_DATABASE_DDB);
|
||||
$this->state = STATE_FRAMEWORK_FAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
// set the class properties based off the template settings for the data
|
||||
$this->templateName = STRING_CLASS_GAT . $_meta[META_TEMPLATE];
|
||||
if (!$this->loadTemplate()) {
|
||||
$this->logger->warn(ERROR_TEMPLATE_INSTANTIATE . $_meta[META_TEMPLATE]);
|
||||
$this->state = STATE_TEMPLATE_ERROR;
|
||||
return;
|
||||
}
|
||||
$this->class = $_meta[META_TEMPLATE]; // set the class to the name of the requested data class
|
||||
|
||||
// get the http resource for connecting to DynamoDB instance
|
||||
if (gasResourceManager::$ddbAvailable and is_null($this->connection)) {
|
||||
$this->connection = gasResourceManager::fetchResource(RESOURCE_DDB);
|
||||
if (!is_object($this->connection)) {
|
||||
$this->logger->fatal(ERROR_RESOURCE_DDB_404);
|
||||
$this->setState(STATE_DB_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// store meta data and client identifier
|
||||
$this->client = STRING_UNDEFINED; // todo: why?
|
||||
if (!empty($_meta)) {
|
||||
$this->metaPayload = $_meta;
|
||||
if (isset($this->metaPayload[META_CLIENT])) {
|
||||
$this->client = $this->metaPayload[META_CLIENT];
|
||||
}
|
||||
}
|
||||
|
||||
// store the event GUID
|
||||
if (isset($this->metaPayload[META_EVENT_GUID])) {
|
||||
$this->eventGUID = $this->metaPayload[META_EVENT_GUID];
|
||||
} else {
|
||||
$this->logger->warn(ERROR_EVENT_GUID_404);
|
||||
}
|
||||
|
||||
// if a GUID/key was passed to the constructor, we need to fetch that record from the db
|
||||
// NOTE: mBEDS code has connecting-to-remote-service (vault) code in this block
|
||||
$this->data = null; // reset the data container
|
||||
if (!empty($_guid) and validateGUID($_guid)) { // if we have a valid guid...
|
||||
if ($this->useCache and gasResourceManager::$cacheAvailable) { // if cache is on and available
|
||||
$this->data = gasCache::get($_guid); // search cache for the key
|
||||
if (!is_null($this->data)) {
|
||||
$this->data = json_decode(gzuncompress($this->data), true);
|
||||
}
|
||||
}
|
||||
if (is_null($this->data)) {
|
||||
$this->guidFetch($_guid);
|
||||
}
|
||||
} else {
|
||||
$this->state = STATE_SUCCESS;
|
||||
$this->status = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected function _createRecord($_data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _fetchRecords($_dd, $_rd = null, $_co = true, $_skip = 0, $_limit = 0, $_sort = null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _updateRecord($_data){
|
||||
|
||||
}
|
||||
|
||||
protected function _deleteRecord($_data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _lockRecord()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _releaseLock()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected function _isLocked()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* guidFetch() -- private method
|
||||
*
|
||||
* this method is (should only be) called from the class constructor and only then if the calling client passes
|
||||
* a guid into the constructor - which the framework interprets as a request to instantiate and populate with the
|
||||
* record designated by the guid - which is the primary key for the ddb table.
|
||||
*
|
||||
* The required input parameter is the guid for the record. Validation (that this is a guid) happens in the
|
||||
* constructor or the calling client.
|
||||
*
|
||||
* First, we build the table name from the current environment and then build the query. The query is just a
|
||||
* key-value-pair fetch but converts into something overly-complicated once we phrase it in ddb syntax. Just
|
||||
* for logging and general readability, we sql-ize the ddb-query and store the string in the designated property.
|
||||
*
|
||||
* If the class is using timers, start the timer
|
||||
* Execute the query - which returns an iterator and not a data set
|
||||
* Log the timer results to the metrics table
|
||||
* parse the return data set and assign it to the $data property
|
||||
*
|
||||
* We exception-wrap the query so we'll return the error as to why the query failed and will log accordingly.
|
||||
*
|
||||
* Next, if cache is enabled for the current class, cache the item after converting the data set to a json
|
||||
* string.
|
||||
*
|
||||
* At all levels, set the state-status values accordingly - these are what should be evaluated by the calling
|
||||
* client on return from the method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_guid
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-21-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function guidFetch(string $_guid)
|
||||
{
|
||||
if ($this->trace) $this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
$this->status = false;
|
||||
$startTime = floatval(0);
|
||||
$tableName = gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] . UDASH . $this->collectionName . $this->ext;
|
||||
$query = [
|
||||
DDB_STRING_CONSISTENT_READ => true,
|
||||
DDB_TABLE_NAME => $tableName,
|
||||
DDB_STRING_EXPR_ATTR_VALS => [
|
||||
':q1' => [
|
||||
$this->fieldTypes[$this->pKey . $this->ext] => $_guid
|
||||
]
|
||||
],
|
||||
DDB_STRING_KEY_COND_EXPR => "$this->pKey$this->ext = :q1"
|
||||
];
|
||||
/** @noinspection SqlNoDataSourceInspection */
|
||||
$this->strQuery = 'DDB:SELECT * FROM ' . $tableName . ' WHERE id' . $this->ext . ' = "' . $_guid . '"';
|
||||
|
||||
// todo - this was coded to see if it worked - next, build a query request array and pass to queryBuilder() and _fetchRecords()
|
||||
// exec the DDB query
|
||||
try {
|
||||
if ($this->useTimers) $startTime = gasStatic::doingTime();
|
||||
/** @var AWS\Result $result */
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
$result = $this->connection->query($query);
|
||||
if ($this->useTimers) $this->logger->metrics($this->strQuery, gasStatic::doingTime($startTime));
|
||||
if ($result[DDB_STRING_COUNT] != 1) {
|
||||
$msg = sprintf(ERROR_DDB_RECORD_COUNT, count($result), 1);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->error($msg);
|
||||
return;
|
||||
}
|
||||
// parse the return data set
|
||||
/** @var array $resultData */
|
||||
$resultData = $result[DDB_STRING_ITEMS];
|
||||
foreach ($resultData as $item) {
|
||||
$record = null;
|
||||
foreach ($item as $key => $value)
|
||||
foreach ($value as $type => $column)
|
||||
$record[$key] = $column;
|
||||
$this->data[] = $record;
|
||||
}
|
||||
} catch (\Aws\Exception\AwsException $e) {
|
||||
$this->eventMessages[] = $e->getMessage();
|
||||
$this->logger->error($e->getMessage());
|
||||
$this->state = STATE_DB_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
// cache the item if cache is enabled for the current class
|
||||
if ($this->useCache and !empty($this->data)) {
|
||||
$cacheData = json_encode($this->data);
|
||||
if (is_null(gasCache::add($this->getColumn($this->pKey), $cacheData))) {
|
||||
$msg = ERROR_CACHE_ADD_FAIL . $this->getColumn($this->pKey);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->error($msg);
|
||||
$this->state = STATE_CACHE_ERROR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->event = DB_EVENT_FETCH;
|
||||
$this->status = true;
|
||||
$this->state = STATE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
private function queryBuilder(array $_query)
|
||||
{
|
||||
if ($this->trace) $this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
$this->status = false;
|
||||
$foundIndex = false;
|
||||
$attribute = '';
|
||||
|
||||
if (!is_array($_query) or empty($_query)) { // '[]' tests true for is_array
|
||||
$msg = ERROR_PARAM_404 . DDB_STRING_QUERY;
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->error($msg);
|
||||
$this->state = STATE_DATA_ERROR;
|
||||
return;
|
||||
}
|
||||
// deal with a single-key query
|
||||
if (count($_query) == 1) {
|
||||
// extract the key value pair
|
||||
foreach ($_query as $k1 => $v1) { // attribute level
|
||||
$attribute = $k1;
|
||||
foreach ($v1 as $k2 => $v2) { // operand level
|
||||
foreach ($v2 as $k3 => $v3) { // operator level
|
||||
// check that the operand is '='
|
||||
if ($k3 != OPERATOR_DDB_EQ) {
|
||||
$this->eventMessages[] = ERROR_DDB_EXP_EQ_Q1;
|
||||
$this->logger->data(ERROR_DDB_EXP_EQ_Q1);
|
||||
$this->state = STATE_DATA_ERROR;
|
||||
return;
|
||||
}
|
||||
if (count($v3) != 1) {
|
||||
$this->eventMessages[] = ERROR_DDB_EXP_VAL_Q1;
|
||||
$this->logger->data(ERROR_DDB_EXP_VAL_Q1);
|
||||
$this->state = STATE_DATA_ERROR;
|
||||
return;
|
||||
}
|
||||
$value = $v3[0]; // grab the search value
|
||||
}
|
||||
}
|
||||
}
|
||||
// we have extracted the search key attribute and the search value...need to find it in one of
|
||||
// the three possible index declarations for the current table (VALIDATE THE INDEX ATTRIBUTE)
|
||||
if (array_key_exists($attribute, $this->indexes) and $this->indexes[$attribute] == DDB_INDEX_HASH) {
|
||||
$foundIndex = 'base';
|
||||
} else {
|
||||
$ca = ['globalIndexes', 'localIndexes'];
|
||||
foreach ($ca as $index) {
|
||||
if (is_array($this->$index)) {
|
||||
foreach ($this->$index as $subIndex) {
|
||||
if (array_key_exists($attribute, $subIndex) and $subIndex[$attribute] == DDB_INDEX_HASH) {
|
||||
$foundIndex = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($foundIndex) break;
|
||||
}
|
||||
}
|
||||
// if (is_array($this->globalIndexes)) {
|
||||
// foreach ($this->globalIndexes as $gIndex) {
|
||||
// if (array_key_exists($attribute, $gIndex) and $gIndex[$attribute] == DDB_INDEX_HASH) {
|
||||
// $foundIndex = true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (!$foundIndex and is_array($this->localIndexes)) {
|
||||
// foreach ($this->localIndexes as $lIndex) {
|
||||
// if (array_key_exists($attribute, $lIndex) and $lIndex[$attribute] == DDB_INDEX_HASH) {
|
||||
// $foundIndex = true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if (!$foundIndex) {
|
||||
$msg = sprintf(ERROR_DDB_NO_HASH_IDX, $attribute);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->data($msg);
|
||||
$this->state = STATE_DATA_ERROR;
|
||||
return;
|
||||
}
|
||||
} elseif (count($_query) == 1) {
|
||||
// todo: query uses the hash and the range
|
||||
|
||||
} else {
|
||||
// todo -- malformed request
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* loadTemplate() -- private method
|
||||
*
|
||||
* this method is invoked by the constructor and serves to load the class template file, assimilating it into
|
||||
* the current instantiation.
|
||||
*
|
||||
* template loads are done on the schema-instantiation level, instead of the core, because of the changes in
|
||||
* the template file(s) across various schemas.
|
||||
*
|
||||
* the method will load the class template and set the class member variables controlled/referenced by the
|
||||
* template.
|
||||
*
|
||||
* successful loading of the template is determined by the return (boolean) value -- on error, a log message
|
||||
* will be generated so it's up to the developer to check logs on fail-returns to see why their template
|
||||
* file was not correctly assimilated.
|
||||
*
|
||||
* The template to be loaded is first derived in the constructor (post validation that the template file
|
||||
* exists) and is pulled from the member variable (also set in the constructor) within this method.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-20-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function loadTemplate():bool
|
||||
{
|
||||
if ($this->trace) $this->logger->trace(STRING_ENT_METH . __METHOD__);
|
||||
|
||||
try {
|
||||
$this->template = new $this->templateName();
|
||||
} catch (Exception $e) {
|
||||
$this->logger->warn($e->getMessage());
|
||||
$this->state = STATE_FRAMEWORK_FAIL;
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (!is_object($this->template)) {
|
||||
$this->logger->warn(ERROR_FILE_404 . $this->templateName);
|
||||
$this->setState(ERROR_FILE_404 . $this->templateName);
|
||||
return (false);
|
||||
}
|
||||
|
||||
if ($this->template->schema != TEMPLATE_DB_DDB) {
|
||||
$this->logger->warn(ERROR_SCHEMA_MISMATCH . $this->template->schema . ERROR_STUB_EXPECTING . TEMPLATE_DB_DDB);
|
||||
$this->setState(ERROR_SCHEMA_MISMATCH . $this->templateName);
|
||||
return (false);
|
||||
}
|
||||
|
||||
// transfer meta data info to current instantiation
|
||||
$this->service = $this->template->service;
|
||||
$this->schema = $this->template->schema;
|
||||
$this->collectionName = $this->template->collection;
|
||||
$this->ext = $this->template->extension;
|
||||
$this->useCache = $this->template->setCache;
|
||||
$this->useDeletes = $this->template->setDeletes;
|
||||
$this->useAuditing = $this->template->setAuditing;
|
||||
$this->useJournaling = $this->template->setJournaling;
|
||||
$this->allowUpdates = $this->template->setUpdates;
|
||||
$this->useDetailedHistory = $this->template->setHistory;
|
||||
$this->defaultStatus = $this->template->setDefaultStatus;
|
||||
$this->searchStatus = $this->template->setSearchStatus;
|
||||
$this->useLocking = $this->template->setLocking;
|
||||
$this->useTimers = ($this->template->setTimers and gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_QUERY_TIMERS]);
|
||||
$this->pKey = $this->template->setPKey;
|
||||
$this->useToken = $this->template->setTokens;
|
||||
$this->cacheExpiry = $this->template->cacheTimer;
|
||||
|
||||
if (isset($this->template->fields) and is_array($this->template->fields)) {
|
||||
foreach ($this->template->fields as $key => $value) {
|
||||
if ($key == DB_HISTORY) {
|
||||
$this->fieldList[] = $key;
|
||||
$this->fieldTypes[$key] = $value;
|
||||
} else {
|
||||
$this->fieldList[] = ($key . $this->ext);
|
||||
$this->fieldTypes[($key . $this->ext)] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->template->indexes) and is_array($this->template->indexes)) {
|
||||
foreach ($this->template->indexes as $key => $value) {
|
||||
$this->indexes[] = ($key . $this->ext);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: validate the global index data
|
||||
if (isset($this->template->globalIndexes) and is_array($this->template->globalIndexes)) {
|
||||
foreach ($this->template->globalIndexes as $key ) {
|
||||
$this->globalIndexes[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
// todo: validate the local index data
|
||||
if (isset($this->template->localIndexes) and is_array($this->template->localIndexes)) {
|
||||
foreach ($this->template->localIndexes as $key) {
|
||||
$this->localIndexes[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($this->template->cacheMap)) {
|
||||
foreach ($this->template->cacheMap as $key => $value) {
|
||||
$this->cacheMap[($key . $this->ext)] = $value;
|
||||
}
|
||||
} else {
|
||||
$this->cacheMap = null;
|
||||
}
|
||||
|
||||
if (!is_null($this->template->binFields)) {
|
||||
foreach ($this->template->binFields as $key) {
|
||||
$this->binaryFields[] = ($key . $this->ext);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->template->selfDestruct) {
|
||||
unset($this->template);
|
||||
}
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* class destructor
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-20-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
//
|
||||
// destructor is registered shut-down function in constructor -- so any recovery
|
||||
// efforts should go in this method.
|
||||
|
||||
// there is no destructor method defined in the core abstraction class, hence
|
||||
// there is no call to that parent destructor in this class.
|
||||
parent::__destruct();
|
||||
}
|
||||
|
||||
}
|
||||
817
classes/gacErrorLogger.class.inc
Normal file
817
classes/gacErrorLogger.class.inc
Normal file
@@ -0,0 +1,817 @@
|
||||
<?php
|
||||
|
||||
use MongoDB\Driver\WriteResult;
|
||||
|
||||
class gacErrorLogger {
|
||||
public bool $haveErrors; // true if we have ERROR errors
|
||||
public bool $haveWarnings; // true if we have WARN errors
|
||||
public bool $haveFatals; // true if we have FATAL errors
|
||||
public array $errStack; // the error stack array
|
||||
public bool $available = false; // boolean indicating service availability
|
||||
public bool $mirror = false; // mirror db log messages to console?
|
||||
public string $status; // dynamic progress indicator
|
||||
private string $service = ''; // defines which service the current instantiation is current running on
|
||||
|
||||
private ?string $eventGUID = ''; // recording the broker event identifier
|
||||
private bool $isMetric = false; // indicates if this is a metrics (as opposed to a log) message
|
||||
private string $res = 'LOGR: '; // console-log label
|
||||
private bool $publishMessage; // do we publish the message remotely or write locally?
|
||||
private string $ext = ''; // class extension (_log or _met)
|
||||
private string $class = ''; // class name of the current collection
|
||||
private array $config; // holds copy of the pgsConfig for mongo
|
||||
private ?object $connection; // mongo DB Driver connection resource
|
||||
private string $dbName; // name of the mongodb
|
||||
private string $collectionName = ''; // mongo table name (log end-point)
|
||||
private array $validTemplates; // names of the collections
|
||||
private string $env = ''; // defines the environment for ddb table names
|
||||
private gacLogClient $abc; // Admin Broker Client -- pointer to the admin broker client class
|
||||
|
||||
public function __construct(string $_eg = null, bool $_pm = true)
|
||||
{
|
||||
$this->status = false;
|
||||
try {
|
||||
register_shutdown_function(array($this, '__destruct'));
|
||||
|
||||
$this->errStack = [];
|
||||
$this->haveErrors = false;
|
||||
$this->haveWarnings = false;
|
||||
$this->haveFatals = false;
|
||||
$this->publishMessage = $_pm;
|
||||
|
||||
$this->eventGUID = (!is_null($_eg) and validateGUID($_eg)) ? $_eg : null;
|
||||
$this->validTemplates = [TEMPLATE_CLASS_LOGS, TEMPLATE_CLASS_METRICS];
|
||||
|
||||
// toss a fatal if the config hasn't been instantiated...
|
||||
if (!isset(gasConfig::$settings) or empty(gasConfig::$settings)) {
|
||||
$this->throwFatal(__FILE__ . '(' . __LINE__ . '): ' . ERROR_CONFIG_404);
|
||||
} elseif (empty(gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MONGODB])) {
|
||||
$this->throwFatal(__FILE__ . '(' . __LINE__ . '): ' . ERROR_CONFIG_RESOURCE_404 . RESOURCE_DDB);
|
||||
}
|
||||
// $this->config = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_DDB];
|
||||
// $this->connection = $this->getNoSQLResource(); // ddb connection
|
||||
$this->config = gasConfig::$settings[CONFIG_DATABASE][CONFIG_DATABASE_MONGODB];
|
||||
$this->connection = gasResourceManager::fetchResource(RESOURCE_MONGO_MASTER, ENV_ADMIN);
|
||||
$this->available = (!is_null($this->connection)) ? true : false;
|
||||
$this->env = gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV];
|
||||
$this->dbName = $this->env . UDASH . $this->config[CONFIG_DATABASE_MONGODB_ADMIN][CONFIG_DATABASE_MONGODB_DB_NAME];
|
||||
// $this->abc = null;
|
||||
$this->status = true;
|
||||
} catch (TypeError | Throwable $e) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
echo getDateTime() . CON_ERROR . $this->res . $hdr . $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* setService() -- public method
|
||||
*
|
||||
* When any class that extends core creates an embedded logger class, which they all should, then the instantiation
|
||||
* class should call this function s.t. the logger class inherits (sloppily) the service defined for the current
|
||||
* class. This will validated later in the function: isServiceLocal() when we're instantiating a class to ensure
|
||||
* that a class can only be instantiated in it's service when we're dealing with appServer and tercero classes.
|
||||
*
|
||||
* There is a single input parameter to the function that is the defined name of the current service. We're not
|
||||
* validating this string value b/c that's happened already within the "parent" class.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_service
|
||||
* @return bool
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 11-04-20 mks DB-171: original coding
|
||||
*
|
||||
*/
|
||||
public function setService(string $_service):bool
|
||||
{
|
||||
if (isset(gasConfig::$settings[$_service]))
|
||||
if (gasConfig::$settings[$_service][CONFIG_IS_LOCAL])
|
||||
$this->service = $_service;
|
||||
else {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$msg = sprintf(ERROR_SERVICE_NOT_LOCAL, $_service);
|
||||
consoleLog('SSER: ', CON_ERROR, $hdr . $msg);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __FILE__);
|
||||
$msg = ERROR_CONFIG_RESOURCE_404 . STRING_SERVICE;
|
||||
consoleLog('SSER: ', CON_ERROR, $hdr . $msg);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* throwFatal() -- private method
|
||||
*
|
||||
* if the logger cannot be properly instantiated, (thereby being unable to log errors in the database), the the
|
||||
* last remaining option is to throw a direMessage (tm) to the console.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_msg -- the text dumped to the php-errors log
|
||||
* @throws Exception
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
* 12-07-17 mks CORE-591: removed errStack dump b/c cached and can be recovered
|
||||
* 01-22-18 mks _INF-139: updated code to php 7.2
|
||||
* 03-02-18 mks CORE-680: deprecated trace logging
|
||||
*
|
||||
*/
|
||||
private function throwFatal(string $_msg): void
|
||||
{
|
||||
$msg = PHP_EOL . '----------------------------------------------------------------------------------------------------' . PHP_EOL;
|
||||
$msg .= ' FATAL ERRORS OCCURRED IN THE ERROR CLASS. EVALUATE, FIX, AND RE-RUN.' . PHP_EOL;
|
||||
$msg .= PHP_EOL . $_msg . PHP_EOL;
|
||||
$msg .= '----------------------------------------------------------------------------------------------------' . PHP_EOL;
|
||||
throw new Exception($msg);
|
||||
}
|
||||
|
||||
|
||||
public function debug(string $_message): void
|
||||
{
|
||||
try {
|
||||
self::set(ERROR_DEBUG, $_message);
|
||||
} catch (Throwable $t) {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
}
|
||||
}
|
||||
public function info(string $_message): void
|
||||
{
|
||||
try {
|
||||
self::set(ERROR_INFO, $_message);
|
||||
} catch (Throwable $t) {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
}
|
||||
}
|
||||
public function data(string $_message): void
|
||||
{
|
||||
try {
|
||||
self::set(ERROR_DATA, $_message);
|
||||
} catch (Throwable $t) {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
}
|
||||
}
|
||||
public function error(string $_message): void
|
||||
{
|
||||
try {
|
||||
self::set(ERROR_ERROR, $_message);
|
||||
} catch (Throwable $t) {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
}
|
||||
}
|
||||
public function warn(string $_message): void
|
||||
{
|
||||
try {
|
||||
self::set(ERROR_WARN, $_message);
|
||||
} catch (Throwable $t) {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
}
|
||||
}
|
||||
public function fatal(string $_message): void
|
||||
{
|
||||
try {
|
||||
self::set(ERROR_FATAL, $_message);
|
||||
} catch (Throwable $t) {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
}
|
||||
}
|
||||
public function metrics(string $_message, float $_time, &$_es = null): void
|
||||
{
|
||||
try {
|
||||
self::set(ERROR_METRICS, $_message, true, $_time, $_es);
|
||||
} catch (Throwable $t) {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set() -- public method
|
||||
*
|
||||
* this method is where most of the work gets done for the class.
|
||||
*
|
||||
* this method accepts a log level and a log message. if AMQP and nosql services are not available (either),
|
||||
* then the message will be output to the console.
|
||||
*
|
||||
* otherwise, we're going to parse the log level against the configuration settings to ensure that we're
|
||||
* publishing messages according to the settings and the current environment. (iow, don't publish debug level
|
||||
* messages while in a production environment)
|
||||
*
|
||||
* RULES:
|
||||
* ------
|
||||
* DEBUG errors are only logged if debug mode is on
|
||||
*
|
||||
* we use debug_backtrace to generate the originating message data points and assemble the message data
|
||||
* (and the meta data for the broker request) into a single array which is then processed and published
|
||||
* to the delayed-write queue (itself a fire-and-forget queue).
|
||||
*
|
||||
* this design differs from previous iterations in that we're no longer trying to preserve an ongoing error
|
||||
* stack - instead we're just considering the incoming message to be the only message currently in existence.
|
||||
*
|
||||
* The input parameters to the method are:
|
||||
*
|
||||
* $_level - which is the message level and a defined constant
|
||||
* $_message - the text of the actual message
|
||||
* $_metrics - (optional, default = false) if true, use the metrics template instead of the logs template
|
||||
* $_t - (optional, default = 0), for metrics, the total query time
|
||||
* $_es - (optional, default = 0), call-by-reference param to store/return the metrics error stack
|
||||
*
|
||||
* There are no return values, either implicitly or explicitly.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_level error level
|
||||
* @param string $_message error message string
|
||||
* @param bool $_metrics defines the event as a metric (instead of an error) event
|
||||
* @param float $_t time, in ms
|
||||
* @param array $_es error stack: call by reference array stack/container
|
||||
* @throws Exception
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
* 07-12-17 mks added log-level values to collection/processing
|
||||
* 12-08-17 mks CORE-591: new throw-fatal processing
|
||||
* 03-02-18 mks CORE-680: deprecated trace logging
|
||||
* 06-08-18 mks CORE-1034: deprecating XML prodBox tag
|
||||
* 07-30-18 mks CORE-774: PHP7.2 exception handling update
|
||||
* 09-24-19 mks DB-136: fixed error in levelValues element assignment to correct constant
|
||||
* 11-04-20 mks DB-171: added service (origin) definition to logging output
|
||||
*
|
||||
*/
|
||||
private function set(string $_level, string $_message, bool $_metrics = false, float $_t = 0, array &$_es = null): void
|
||||
{
|
||||
$this->errStack = [];
|
||||
|
||||
$levelValues = [
|
||||
ERROR_EVENT => ERROR_EVENT_VAL,
|
||||
ERROR_METRICS => ERROR_METRICS_VAL,
|
||||
ERROR_DEBUG => ERROR_DEBUG_VAL,
|
||||
ERROR_DATA => ERROR_DATA_VAL,
|
||||
ERROR_INFO => ERROR_INFO_VAL,
|
||||
ERROR_ERROR => ERROR_ERROR_VAL,
|
||||
ERROR_WARN => ERROR_WARN_VAL,
|
||||
ERROR_FATAL => ERROR_FATAL_VAL
|
||||
];
|
||||
|
||||
if (!array_key_exists($_level, $levelValues)) {
|
||||
$this->throwFatal(__FILE__ . COLON . __LINE__ . COLON . sprintf(ERROR_UNKNOWN_KEY, $_level, LOG_VALUE));
|
||||
$_level = ERROR_ERROR;
|
||||
}
|
||||
|
||||
// the system is up - so create the error message request for publication to the DW broker
|
||||
$_message = empty($_message) ? ERROR_DATA_INPUT_EMPTY : trim($_message);
|
||||
switch ($_level) {
|
||||
case ERROR_DEBUG :
|
||||
$saveError = gasConfig::$settings[CONFIG_DEBUG] and !(gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] == ENV_PRODUCTION);
|
||||
break;
|
||||
|
||||
case ERROR_DATA :
|
||||
case ERROR_INFO :
|
||||
case ERROR_METRICS :
|
||||
$saveError = true;
|
||||
break;
|
||||
|
||||
case ERROR_ERROR :
|
||||
$this->haveErrors = true;
|
||||
$saveError = true;
|
||||
break;
|
||||
|
||||
case ERROR_WARN :
|
||||
$this->haveWarnings = true;
|
||||
$saveError = true;
|
||||
break;
|
||||
|
||||
case ERROR_FATAL :
|
||||
$this->haveFatals = true;
|
||||
$saveError = true;
|
||||
break;
|
||||
|
||||
default :
|
||||
$saveError = true;
|
||||
$_level = ERROR_INFO;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$saveError) return;
|
||||
|
||||
try {
|
||||
if ($_level == ERROR_METRICS) {
|
||||
$this->isMetric = true;
|
||||
$this->setCollection(TEMPLATE_CLASS_METRICS);
|
||||
} else {
|
||||
$this->setCollection();
|
||||
}
|
||||
} catch (Throwable $t) {
|
||||
consoleLog($this->res, CON_ERROR, ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage());
|
||||
}
|
||||
|
||||
if (is_array($_message)) {
|
||||
$_message = implode('<br />', $_message);
|
||||
}
|
||||
$backTrace = debug_backtrace();
|
||||
for ($index = 0; $index < 3; $index++) {
|
||||
if (isset($backTrace[$index][STRING_FUNCTION]) and $backTrace[$index][STRING_FUNCTION] != STRING_SET)
|
||||
break;
|
||||
}
|
||||
// if (isset($backTrace[2][ERROR_FILE])) {
|
||||
// $index = 2;
|
||||
// } elseif (isset($backTrace[1][ERROR_FILE])) {
|
||||
// $index = 1;
|
||||
// } else {
|
||||
// $index = 0;
|
||||
// }
|
||||
$errStack = null;
|
||||
if (empty($this->errStack)) $this->errStack = array();
|
||||
if ($_level == ERROR_METRICS) @$errStack[(LOG_EVENT . $this->ext)] = EVENT_METRICS;
|
||||
@$errStack[(LOG_FILE . $this->ext)] = $this->service . ARROW . $backTrace[$index][ERROR_FILE];
|
||||
@$errStack[(LOG_LINE . $this->ext)] = $backTrace[$index][ERROR_LINE];
|
||||
@$errStack[(LOG_METHOD . $this->ext)] = $backTrace[$index+1][STRING_FUNCTION];
|
||||
@$errStack[(LOG_CLASS . $this->ext)] = $backTrace[$index+1][ERROR_CLASS];
|
||||
@$errStack[(LOG_LEVEL . $this->ext)] = $_level;
|
||||
@$errStack[(LOG_VALUE . $this->ext)] = $levelValues[$_level];
|
||||
@$errStack[(LOG_MESSAGE . $this->ext)] = utf8_encode($_message);
|
||||
if (isset($this->eventGUID))
|
||||
@$errStack[(DB_EVENT_GUID . $this->ext)] = $this->eventGUID;
|
||||
if ($_metrics) {
|
||||
@$errStack[(LOG_TIMER . $this->ext)] = $_t;
|
||||
$_es = $backTrace;
|
||||
}
|
||||
$errStack[(LOG_CREATED . $this->ext)] = time();
|
||||
array_push($this->errStack, $errStack);
|
||||
|
||||
try {
|
||||
$this->writeLogMessage();
|
||||
if ($this->mirror) {
|
||||
consoleLog($this->res, CON_ERROR, $_message);
|
||||
}
|
||||
} catch (Throwable $t) {
|
||||
consoleLog($this->res, CON_ERROR, ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* writeLogMessage() -- public static method
|
||||
*
|
||||
* this is the record-create method for saving a log event.
|
||||
*
|
||||
* There are three input parameters to the method, all of which are required:
|
||||
*
|
||||
* $_data -- the data payload as received by the broker in associative array format
|
||||
* $_meta -- the meta payload as received by the broker in associative array format
|
||||
* $_where -- string (use the system constant, please) that defines the collection destination
|
||||
*
|
||||
* first thing we do is set the collection destination by passing the $_where input parameter to the
|
||||
* private setCollection() method.
|
||||
*
|
||||
* if we (self) are not available, then return immediately where the calling client should assume that the
|
||||
* logging services are not available and post the necessary console message.
|
||||
*
|
||||
* Validate the $_data payload by assigning the contents, filtering the payload through a validation array,
|
||||
* into a temp variable...
|
||||
*
|
||||
* next, insert the generated sequence key into the temp array structure and add the created-date timestamp...
|
||||
*
|
||||
* finally, insert the record into the designated collection, trapping any nosql exception raised in our fatal
|
||||
* handler so that the (error) results are saved to the console log.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param bool $_im -- is Metric -- should only be set to true from adminIn broker event call
|
||||
* @throws Exception
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
* 06-14-17 mks refactored for dynamodb
|
||||
* 07-05-17 mks CORE-463: refactored for RMQ and mongoDB
|
||||
* 07-07-17 mks CORE-463: switch collections on-the-fly for adminIn Metrics event call
|
||||
* 12-06-17 mks CORE-591: caching log messages based on XML config params, w/console logging on errors
|
||||
* 01-22-18 mks _INF-139: fixed bug where when caching is disabled, the current error wasn't being
|
||||
* added to the error stack.
|
||||
* 03-01-18 mks CORE-689: removed env tag from collection name
|
||||
* 07-30-18 mks CORE-774: converted to PHP7.2 typeError trapping/processing
|
||||
*
|
||||
*/
|
||||
public function writeLogMessage(bool $_im = false)
|
||||
{
|
||||
// if the logger service is unavailable or we don't have a message to publish, then return
|
||||
if (!$this->available or empty($this->errStack)) return;
|
||||
|
||||
$this->status = false;
|
||||
$oe = $oc = $os = '';
|
||||
$maxMsgCount = gasConfig::$settings[CONFIG_CACHE][CONFIG_CACHE_LOG_BUFFER_COUNT];
|
||||
$msgBufferOn = boolval(gasConfig::$settings[CONFIG_CACHE][CONFIG_CACHE_LOG_BUFFER]);
|
||||
$whichBuffer = ($this->isMetric) ? CONFIG_CACHE_METRICS_BUFFER : CONFIG_CACHE_LOG_BUFFER;
|
||||
$whichBufferCounter = ($this->isMetric) ? CONFIG_CACHE_METRICS_BUFFER_COUNT : CONFIG_CACHE_LOG_BUFFER_COUNT;
|
||||
|
||||
// if (empty($aryData[DB_PKEY])) {
|
||||
// $this->errStack[(DB_PKEY . $this->ext)] = guid();
|
||||
// }
|
||||
// $this->errStack[(LOG_CREATED . $this->ext)] = time();
|
||||
|
||||
// admin service is remote - either cache or publish the message
|
||||
if ($this->publishMessage) {
|
||||
try {
|
||||
$currMsgCount = gasCache::sysGet($whichBufferCounter);
|
||||
$msgBuffer = gasCache::sysGet($whichBuffer);
|
||||
// remove cache data
|
||||
gasCache::sysDel($whichBuffer);
|
||||
gasCache::sysDel($whichBufferCounter);
|
||||
} catch (Throwable $t) {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// validate the message buffer fetched from cache
|
||||
if (!empty($msgBuffer) and !is_array($msgBuffer)) {
|
||||
$msg = basename(__FILE__) . COLON . __LINE__ . COLON;
|
||||
$msg .= sprintf(ERROR_CACHE_DATA_MALFORMED, 'array', CONFIG_CACHE_LOG_BUFFER, gettype($msgBuffer));
|
||||
$msg .= PHP_EOL . 'Dump: ' . PHP_EOL;
|
||||
$msg .= var_export($msgBuffer, true);
|
||||
$msg .= PHP_EOL;
|
||||
$this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . $msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($currMsgCount === false) {
|
||||
/** @noinspection PhpUnusedLocalVariableInspection */
|
||||
$currMsgCount = 0;
|
||||
}
|
||||
if (false === $msgBuffer) $msgBuffer = [];
|
||||
$msgBuffer = [...$msgBuffer, ...$this->errStack];
|
||||
$currMsgCount = count($msgBuffer);
|
||||
|
||||
// determine if we're going to publish or cache the message buffer
|
||||
$publish = (!$msgBufferOn or $currMsgCount >= $maxMsgCount) ? true : false;
|
||||
|
||||
if ($publish) {
|
||||
try {
|
||||
// $this->abc = new gacAdminClientIn(__METHOD__ . COLON . __LINE__);
|
||||
$this->abc = new gacLogClient();
|
||||
if (!$this->abc->status) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
$msg = ERROR_FAILED_TO_INSTANTIATE . RESOURCE_ADMIN_CLIENT;
|
||||
consoleLog($this->res, CON_ERROR, $hdr . $msg);
|
||||
return;
|
||||
}
|
||||
} catch (Throwable $t) {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
return;
|
||||
}
|
||||
$request = [
|
||||
BROKER_REQUEST => ($this->isMetric) ? BROKER_REQUEST_MET : BROKER_REQUEST_LOG,
|
||||
BROKER_DATA => $msgBuffer,
|
||||
BROKER_META_DATA => [
|
||||
META_TEMPLATE => ($this->isMetric) ? TEMPLATE_CLASS_METRICS : TEMPLATE_CLASS_LOGS,
|
||||
META_CLIENT => CLIENT_SYSTEM
|
||||
]
|
||||
];
|
||||
if (!empty($this->eventGUID)) $request[BROKER_META_DATA][META_EVENT_GUID] = $this->eventGUID;
|
||||
try {
|
||||
$route = (!$this->isMetric) ? EXCHANGE_SOURCE_LOGS : EXCHANGE_SOURCE_METRICS;
|
||||
$this->abc->call(gzcompress(json_encode($request)), $route);
|
||||
if (is_object($this->abc)) $this->abc->__destruct();
|
||||
unset($this->abc);
|
||||
} catch (TypeError | Throwable $t) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
consoleLog($this->res, CON_ERROR, $hdr . $t->getMessage());
|
||||
return;
|
||||
}
|
||||
unset($this->abc);
|
||||
// $this->abc = null;
|
||||
$this->isMetric = false;
|
||||
// if (gasConfig::$settings[CONFIG_DEBUG]) {
|
||||
// $msg = sprintf(SUCCESS_CACHE_LOG_DUMP, $currMsgCount);
|
||||
// consoleLog($this->res, CON_SUCCESS, $msg);
|
||||
// }
|
||||
} else {
|
||||
// update the current message buffer and message buffer counter and re-cache
|
||||
$msgBuffer = [...$msgBuffer, ...$this->errStack];
|
||||
$currMsgCount = count($msgBuffer);
|
||||
try {
|
||||
if (!gasCache::sysAdd($whichBuffer, $msgBuffer)) {
|
||||
$this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_CACHE_ADD_FAIL . $whichBuffer);
|
||||
return;
|
||||
}
|
||||
if (!gasCache::sysAdd($whichBufferCounter, $currMsgCount)) {
|
||||
$this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_CACHE_ADD_FAIL . $whichBufferCounter . COLON . $currMsgCount);
|
||||
return;
|
||||
}
|
||||
} catch (Throwable $t) {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__) . ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// write the message directly to mongodb - start by checking the mongo resource
|
||||
if (is_null($this->connection)) {
|
||||
// if we "lost" the resource, attempt to reconnect
|
||||
$this->connection = gasResourceManager::fetchResource(RESOURCE_MONGO_MASTER, ENV_ADMIN);
|
||||
// if we can't reconnect, throw a fatal and exit
|
||||
if (is_null($this->connection)) {
|
||||
$this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_MONGO_CONNECT);
|
||||
}
|
||||
}
|
||||
try {
|
||||
$record = new MongoDB\Driver\BulkWrite();
|
||||
foreach ($this->errStack as $errorMessage)
|
||||
$record->insert($errorMessage);
|
||||
if ($_im) {
|
||||
$oc = $this->collectionName;
|
||||
$oe = $this->ext;
|
||||
$os = $this->class;
|
||||
$this->ext = COLLECTION_MONGO_METRICS_EXT;
|
||||
$this->collectionName = COLLECTION_MONGO_METRICS . $this->ext;
|
||||
$this->class = COLLECTION_MONGO_METRICS;
|
||||
} else {
|
||||
$this->ext = COLLECTION_MONGO_LOGS_EXT;
|
||||
$this->collectionName = COLLECTION_MONGO_LOGS . $this->ext;
|
||||
$this->class = COLLECTION_MONGO_LOGS;
|
||||
}
|
||||
/** @var WriteResult $result */
|
||||
$result = $this->connection->executeBulkWrite($this->dbName . DOT . $this->collectionName, $record);
|
||||
if ($_im) {
|
||||
$this->ext = $oe;
|
||||
$this->collectionName = $oc;
|
||||
$this->class = $os;
|
||||
}
|
||||
unset($record);
|
||||
if ($result->getInsertedCount() != 1) {
|
||||
$msg = __CLASS__ . COLON . __LINE__ . COLON;
|
||||
$msg .= sprintf(ERROR_MONGO_INSERT_COUNT, 1, $result->getInsertedCount());
|
||||
echo getDateTime() . CON_ERROR . $this->res . $msg . PHP_EOL;
|
||||
// todo -- eventManger should be invoked here
|
||||
} else {
|
||||
$this->status = true;
|
||||
}
|
||||
} catch (MongoDB\Driver\Exception\BulkWriteException $e) {
|
||||
$this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_MONGO_EXCEPTION_BULK_WRITE . PHP_EOL . $e->getMessage());
|
||||
} catch (MongoDB\Driver\Exception\InvalidArgumentException $e) {
|
||||
$this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_MONGO_EXCEPTION_INVALID_ARGS . PHP_EOL . $e->getMessage());
|
||||
} catch (MongoDB\Driver\Exception\ConnectionException $e) {
|
||||
$this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_MONGO_EXCEPTION_CONNECTION . PHP_EOL .$e->getMessage());
|
||||
} catch (MongoDB\Driver\Exception\RuntimeException $e) {
|
||||
$this->throwFatal(basename(__METHOD__) . AT . __LINE__ . COLON . ERROR_MONGO_EXCEPTION_RUNTIME . PHP_EOL . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* setCollection() -- private method
|
||||
*
|
||||
* this is a private method, always called by the writeLogMessage() method, that sets the collection destination
|
||||
* for the current request. As of this writing, the logger handles all writes to both the log (pgsLogs_log) and
|
||||
* metrics (pgsMetrics_met) collections. Based on the data passed in the error-message, we set the collection
|
||||
* destination in this method, along with other member variables that are collection dependent.
|
||||
*
|
||||
* the method has a single input parameter, which defaults to a known constant, that is the destination collection.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_which
|
||||
* @throws Exception
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
* 06-14-17 mks updated for ddb, dynamic environments
|
||||
* 07-05-17 mks CORE-463: converted to mongodb
|
||||
* 03-01-18 mks CORE-689: removed env tags from db name
|
||||
*
|
||||
*/
|
||||
private function setCollection(string $_which = TEMPLATE_CLASS_LOGS): void
|
||||
{
|
||||
if (!in_array($_which, $this->validTemplates)) {
|
||||
$this->throwFatal(ERROR_INVALID_TEMPLATE . $_which);
|
||||
} else {
|
||||
if ($_which == TEMPLATE_CLASS_LOGS) {
|
||||
$this->ext = COLLECTION_MONGO_LOGS_EXT;
|
||||
$this->collectionName = COLLECTION_MONGO_LOGS . $this->ext;
|
||||
$this->class = COLLECTION_MONGO_LOGS;
|
||||
} else {
|
||||
$this->ext = COLLECTION_MONGO_METRICS_EXT;
|
||||
$this->collectionName = COLLECTION_MONGO_METRICS . $this->ext;
|
||||
$this->class = COLLECTION_MONGO_METRICS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getLog() - public method
|
||||
*
|
||||
* getLog is the method that is used to fetch log (or Metrics) records from the mongo collection.
|
||||
*
|
||||
* The method has two required parameters:
|
||||
*
|
||||
* $_lines - integer value that indicates the number of log entries to retrieve - defaults to the system constant
|
||||
* $_where - defines which collection to fetch from
|
||||
*
|
||||
* Method opens a channel/connection to mongodb and fetches N lines from the collection specified by the
|
||||
* input parameter.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param int $_lines
|
||||
* @param string $_where
|
||||
* @return null|string
|
||||
* @throws Exception
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-05-17 mks CORE-463: original coding
|
||||
* 09-08-17 mks CORE-529: added event guids to the generated output for dumper
|
||||
* 07-30-18 mks CORE-774: PHP7.2 Exception Compliance
|
||||
*
|
||||
*/
|
||||
public function getLog($_lines, $_where): ?string
|
||||
{
|
||||
if (!in_array($_where, $this->validTemplates)) {
|
||||
$msg = ERROR_MONGO_TEMPLATE_INVALID . $_where;
|
||||
return($msg);
|
||||
}
|
||||
try {
|
||||
$this->setCollection($_where);
|
||||
} catch (Throwable $t) {
|
||||
consoleLog($this->res, CON_ERROR, ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage());
|
||||
}
|
||||
|
||||
if (!$this->available) {
|
||||
return(null); // returning on false implicitly generates a console error message by the calling client
|
||||
}
|
||||
|
||||
if (!is_numeric($_lines) or $_lines < 0) {
|
||||
$_lines = intval(MONGO_LOG_MAX_LINES);
|
||||
} else {
|
||||
$_lines = intval($_lines);
|
||||
}
|
||||
$mongoData = null;
|
||||
$returnData = null;
|
||||
$cursor = null;
|
||||
|
||||
try {
|
||||
$options = [
|
||||
STRING_SORT => [(LOG_CREATED . $this->ext) => -1],
|
||||
STRING_LIMIT => $_lines
|
||||
];
|
||||
$filter = [];
|
||||
$nameSpace = $this->dbName . DOT . $this->collectionName;
|
||||
$readPreference = new MongoDB\Driver\ReadPreference($this->config[CONFIG_DATABASE_MONGODB_ADMIN][CONFIG_DATABASE_MONGODB_SECONDARY_RP]);
|
||||
$query = new MongoDB\Driver\Query($filter, $options);
|
||||
$cursor = $this->connection->executeQuery($nameSpace, $query, $readPreference);
|
||||
} catch (Throwable | TypeError $e) {
|
||||
$this->throwFatal(__FILE__ . COLON . __LINE__ . COLON . ERROR_MONGO_EXCEPTION_INVALID_ARGS . PHP_EOL . $e->getMessage());
|
||||
}
|
||||
if (!is_null($cursor)) {
|
||||
foreach ($cursor as $property) {
|
||||
$property = (array) $property;
|
||||
$returnData .= '<div class="rowMeta">'; // note: css is defined in the utilities directory
|
||||
$returnData .= getDateTime($property[(LOG_CREATED . $this->ext)]) . ' - ';
|
||||
// $returnData .= date(TIME_DATE_FORMAT, $row[(META_SESSION_DATE . self::$ext)]->sec) . ' - ';
|
||||
|
||||
// add error label as a span: warn/error/fatal...
|
||||
try {
|
||||
$returnData .= self::getErrorLabel($property[(LOG_LEVEL . $this->ext)]);
|
||||
} catch (TypeError $t) {
|
||||
consoleLog($this->res, CON_ERROR, ERROR_TYPE_EXCEPTION . COLON . $t->getMessage());
|
||||
}
|
||||
$returnData .= ' ' . $property[(ERROR_FILE . $this->ext)] . '(' . $property[(ERROR_LINE . $this->ext)] . ')';
|
||||
$cd = '';
|
||||
if (!empty($property[(ERROR_CLASS . $this->ext)])) $cd = ' class[' . $property[(ERROR_CLASS . $this->ext)] . ']';
|
||||
if (!empty($property[(ERROR_METHOD . $this->ext)])) $cd .= '.method(' . $property[(ERROR_METHOD . $this->ext)] . ')</div>';
|
||||
$returnData .= $cd;
|
||||
$returnData .= '<div class="rowData">' . htmlentities($property[(ERROR_MESSAGE . $this->ext)]);
|
||||
if ($_where == TEMPLATE_CLASS_METRICS) {
|
||||
$returnData .= ' - ' . $property[(DB_TIMER . $this->ext)] . ' or ';
|
||||
$returnData .= ($property[(DB_TIMER . $this->ext)] * NUMBER_MS_PER_SEC) . 'ms';
|
||||
}
|
||||
$returnData .= '</div>';
|
||||
$returnData .= '<div class="rowHist">';
|
||||
if (!empty($property[(DB_EVENT_GUID . $this->ext)])) {
|
||||
$returnData .= 'Event ID: ' . $property[(DB_EVENT_GUID . $this->ext)];
|
||||
}
|
||||
// foreach($row[(TEMPLATE_HISTORY . $this->ext)] as $histRec) {
|
||||
// $returnData .= date('Y-M-d h:i:s', $histRec[META_SESSION_DATE]->sec);// . ' (';
|
||||
// if (!is_null($row[(MONGO_LOG_EVENT_GUID . $this->ext)]))
|
||||
// $returnData .= ', Event ID: ' . $row[(MONGO_LOG_EVENT_GUID . $this->ext)];
|
||||
// $returnData .= $histRec[META_SESSION_EVENT] . ') from (';
|
||||
// $returnData .= $histRec[META_SESSION_IP] . '): ';
|
||||
// $returnData .= ((isset($histRec[META_SESSION_ID])) ? $histRec[META_SESSION_ID] : $histRec[META_CLIENT_ID]) . '<br />';
|
||||
// }
|
||||
$returnData .= '</div><br />';
|
||||
}
|
||||
}
|
||||
return ($returnData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getErrorLabel() - public method
|
||||
*
|
||||
* build an association between known error types and a color-key for output.
|
||||
*
|
||||
* if the error does not exist, return black.
|
||||
*
|
||||
* in all cases, return an HTML SPAN tag coded to the selected color.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $errorType
|
||||
* @return string
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function getErrorLabel(string $errorType):string
|
||||
{
|
||||
// set the error level text-color
|
||||
$errorColorMap = [
|
||||
ERROR_DEBUG => '#008000', // green
|
||||
ERROR_METRICS => '#00FF00', // black
|
||||
ERROR_DATA => '#0000FF', // black
|
||||
ERROR_INFO => '#000080', // navy
|
||||
ERROR_ERROR => '#800080', // purple
|
||||
ERROR_FATAL => '#FF0000', // red
|
||||
ERROR_WARN => '#F47E1C', // orange,
|
||||
ERROR_EVENT => '#FF00CC', // pink
|
||||
];
|
||||
|
||||
$cssColor = (!empty($errorColorMap[$errorType])) ? $errorColorMap[$errorType] : '#0';
|
||||
|
||||
return '<span style="color:' . $cssColor . ';">' . strtoupper($errorType) . '</span>';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- public method
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-18-15 mks original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public method
|
||||
*
|
||||
* As of PHP 5.3.10, destructors are not run on shutdowns caused by fatal errors - since the destructor is
|
||||
* now registered in the constructor method, recovery and/or clean-up efforts should go into this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-18-15 mks original coding
|
||||
* 05-11-16 mks ome-287: support for dynamic resource management
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
|
||||
}
|
||||
1585
classes/gacFactory.class.inc
Normal file
1585
classes/gacFactory.class.inc
Normal file
File diff suppressed because it is too large
Load Diff
172
classes/gacLogClient.class.inc
Normal file
172
classes/gacLogClient.class.inc
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
/**
|
||||
* gacLogClient -- class definition
|
||||
*
|
||||
* this is the class for declaring a logClient for use in testing, or within the framework when we need to publish
|
||||
* a log event to another queue.
|
||||
*
|
||||
* This class simply abstracts the RabbitMQ processes so that you don't have to re-write all the RMQ code every
|
||||
* time you want to publish a message to the log exchange.
|
||||
*
|
||||
* IMPORTANT NOTE:
|
||||
* ---------------
|
||||
* Whenever you add a qualifying queue to the pantheon, you'll need to update the constructor class, adding the queue
|
||||
* name to the $validQueues member, and to the switch-case statement that assigns the correct environment.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-18-19 mks DB-136: original coding
|
||||
* 12-04-19 mks DB-140: PHP 7.4 compliance
|
||||
* 01-07-20 mks DB-150: PHP 7.4 member variable casting
|
||||
*
|
||||
*/
|
||||
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Exception\AMQPRuntimeException;
|
||||
use PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
|
||||
|
||||
class gacLogClient {
|
||||
private ?object $rabbitConnection;
|
||||
private AMQPChannel $rabbitChannel;
|
||||
private string $res = 'BRCL: ';
|
||||
// if you add to the log-exchange bindings, for either service or source, remember to update these arrays as needed
|
||||
private array $validTypes = [ EXCHANGE_SOURCE_LOGS, EXCHANGE_SOURCE_METRICS, STAR ];
|
||||
public string $status;
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* the constructor instantiates the class and establishes a connection to the RMQ Log Exchange.
|
||||
*
|
||||
* other client classes, such as BrokerClient, require a queue name to be passed to the constructor because these
|
||||
* clients are connecting directly to the queues to publish an event. This client, instead, connects to the
|
||||
* log exchange (instead of a queue) and publishes to the exchange.
|
||||
*
|
||||
* Within the bindings for the exchange which are coded in the brokers for each of the exchange queues, are the
|
||||
* configuration directives for how messages are routed by the exchange to the destination queues. Messages
|
||||
* published to the exchange can be routed to one, several, or all of the queues bound to the exchange.
|
||||
*
|
||||
* That is why there isn't a string parameter passed to this class' constructor - because this client connects
|
||||
* to the exchange and not to a broker specified by the input parameter.
|
||||
*
|
||||
* method returns an implicit boolean via a class member (status) indicating whether or not the resource management
|
||||
* was successful and attempts to provide diagnostics via logging, cli output, or via the status member variable.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-18-19 mks DB-136: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
register_shutdown_function(array($this, '__destruct'));
|
||||
$this->status = false;
|
||||
try {
|
||||
// fetch the AMQPStreamConnection to the Admin service
|
||||
$this->rabbitConnection = gasResourceManager::fetchResource(RESOURCE_ADMIN);
|
||||
if (is_null($this->rabbitConnection)) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
consoleLog($this->res, CON_ERROR, $hdr . ERROR_RESOURCE_404 . RESOURCE_ADMIN);
|
||||
return;
|
||||
}
|
||||
$this->rabbitChannel = $this->rabbitConnection->channel();
|
||||
// connect the channel to the logging exchange
|
||||
$this->rabbitChannel->exchange_declare(EXCHANGE_NAME_TOPIC_LOGS, EXCHANGE_TYPE_TOPIC, false, false, false);
|
||||
$this->status = true;
|
||||
} catch (AMQPRuntimeException | AMQPTimeoutException | Throwable $t) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
consoleLog($this->res, CON_ERROR, $hdr . ERROR_THROWABLE_EXCEPTION);
|
||||
consoleLog($this->res, CON_ERROR, $hdr . $t->getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* call() -- public method
|
||||
*
|
||||
* This method is invoked outside of the class and is the entry point for publishing a message request to the
|
||||
* logging exchange. It creates a new AMQP message and publishes it to the exchange, defined in the constructor),
|
||||
* and then blocks-and-waits for a response from the remote (vault) service.
|
||||
*
|
||||
* There are two input parameters to this method:
|
||||
*
|
||||
* $_data -- this is the payload data that, untouched, is converted into an AMQPMessage class object
|
||||
* $_route -- this defines how the exchange will handle the incoming message (<service>.<source> format)
|
||||
*
|
||||
* For exchange routing, the $_route is required and critical for delivering a successful message request to
|
||||
* the logging exchange. The following values are valid routes with the default route set to STAR:
|
||||
*
|
||||
* EXCHANGE_SOURCE_METRICS, EXCHANGE_SOURCE_LOGS, STAR
|
||||
*
|
||||
* Publishing a message is exception trapped and will generate a log message at the warn level if tripped.
|
||||
*
|
||||
* The method returns a boolean to the calling client if the message was successfully published to the exchange.
|
||||
* Since logging is fire-n-forget, we can't know if the message was accepted... if a false value is returned,
|
||||
* then the client should check the console log as their request failed routing validation.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $_data -- the payload to be converted to an AMQPMessage class object
|
||||
* @param $_route -- The declared route for the message request ( defaults to: * )
|
||||
*
|
||||
* @return bool -- indicates if the message was successfully published or not
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-18-19 mks DB-136: original coding
|
||||
*
|
||||
*/
|
||||
public function call(string $_data, string $_route = STAR): bool
|
||||
{
|
||||
// validate the routing string for the exchange...
|
||||
if (!in_array($_route, $this->validTypes)) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
$msg = sprintf(ERROR_SERVICE_SOURCE_UNK, $_route);
|
||||
consoleLog($this->res, CON_ERROR, $hdr . $msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
// create and publish the message to the logging exchange
|
||||
try {
|
||||
$rabbitMessage = new AMQPMessage((string)$_data);
|
||||
$this->rabbitChannel->basic_publish($rabbitMessage, EXCHANGE_NAME_TOPIC_LOGS, $_route);
|
||||
consoleLog($this->res, CON_SUCCESS, SUCCESS_PUBLISHED . $_route);
|
||||
} catch (AMQPTimeoutException | AMQPRuntimeException | Throwable $e) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
consoleLog($this->res, CON_ERROR, $hdr . $e->getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
// As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
//
|
||||
// destructor is registered shut-down function in constructor -- so any recovery
|
||||
// efforts should go in this method.
|
||||
try {
|
||||
$this->rabbitChannel->close();
|
||||
$this->rabbitConnection->close();
|
||||
} catch (AMQPTimeoutException | AMQPRuntimeException | Throwable $t) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
consoleLog($this->res, CON_ERROR, $hdr . ERROR_THROWABLE_EXCEPTION);
|
||||
consoleLog($this->res, CON_ERROR, $hdr . $t->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
346
classes/gacMeta.class.inc
Normal file
346
classes/gacMeta.class.inc
Normal file
@@ -0,0 +1,346 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class gacMeta -- GivingAssistant Class Meta
|
||||
*
|
||||
* meta data is a class pseudo-template definition which defines the meta-data fields, and their respective types,
|
||||
* that are added to every collection.
|
||||
*
|
||||
* These fields (with the exception of the status field) are usually masked from the user and are managed solely by
|
||||
* the framework although some of the meta field data must be fed to the framework via the published request.
|
||||
*
|
||||
* by defining the meta-data as a class, we relieve ourselves of the responsibility of having to explicitly declare
|
||||
* the meta data in every defined class, and changing the meta data is easier because a single origin point.
|
||||
*
|
||||
* NOTES:
|
||||
* ------
|
||||
* The meta data sub-array is referenced in all collections via the HISTORY column.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-09-17 mks original coding
|
||||
* 01-24-18 mks _INF-139: added BROKER_REQUEST_MIGRATION to meta skip-check
|
||||
* 03-02-18 mks CORE-680: deprecated trace logging
|
||||
* 05-04-18 mks _INF-188: updated meta fields for some undocumented feature fun
|
||||
* 07-31-18 mks CORE-774: PHP7.2 exception handling
|
||||
* 11-15-18 mks DB-63: updated with new meta fields
|
||||
* 12-06-18 mks DB-55: imported validateMetaFields() from gasStatic, refactored, and deprecated the
|
||||
* previous method: validateMeta()
|
||||
* 12-12-18 mks DB-77: added undoc'd audit members for env and audit checks
|
||||
* 02-04-19 mks DB-108: added CLIENT_UNIT to valid client list
|
||||
* 04-02-19 mks DB-116: added META_AUDIT_EVENT to valid client list
|
||||
* 01-07-20 mks DB-150: PHP7.4 member variable type-casting
|
||||
* 03-25-20 mks PD-18: added support for sessionID
|
||||
* 06-02-20 mks ECI-103: added support for API client partners
|
||||
*
|
||||
*/
|
||||
class gacMeta {
|
||||
public array $fields = [
|
||||
META_TEMPLATE => DATA_TYPE_STRING,
|
||||
META_DO_CACHE => DATA_TYPE_BOOL,
|
||||
META_SKIP => DATA_TYPE_INTEGER,
|
||||
META_LIMIT => DATA_TYPE_INTEGER,
|
||||
META_LIMIT_OVERRIDE => DATA_TYPE_INTEGER,
|
||||
META_SYSTEM_NOTES => DATA_TYPE_STRING,
|
||||
META_CLIENT => DATA_TYPE_STRING,
|
||||
META_TARGET_ENV => DATA_TYPE_STRING,
|
||||
META_SESSION_IP => DATA_TYPE_STRING,
|
||||
META_SESSION_ID => DATA_TYPE_STRING,
|
||||
META_CLIENT_IP => DATA_TYPE_STRING,
|
||||
META_EVENT_GUID => DATA_TYPE_STRING,
|
||||
META_SESSION_GUID => DATA_TYPE_STRING,
|
||||
META_USER_GUID => DATA_TYPE_STRING,
|
||||
META_USER_INFO => DATA_TYPE_STRING,
|
||||
META_BROKER_CHILD_GUID => DATA_TYPE_STRING,
|
||||
META_BROKER_GROOT => DATA_TYPE_STRING,
|
||||
META_SESSION_DATE => DATA_TYPE_INTEGER,
|
||||
META_SESSION_EVENT => DATA_TYPE_STRING,
|
||||
META_SESSION_MISC => DATA_TYPE_STRING,
|
||||
META_SESSION_LOCATION => DATA_TYPE_STRING,
|
||||
META_SESSION_DAEMON => DATA_TYPE_INTEGER, // todo: fix that this currently isn't being used
|
||||
META_BROKER_SERVICE => DATA_TYPE_STRING,
|
||||
META_DONUT_FILTER => DATA_TYPE_INTEGER,
|
||||
META_AUDIT_EVENT => DATA_TYPE_INTEGER,
|
||||
META_SKIP_AUDIT => DATA_TYPE_INTEGER,
|
||||
CLIENT_AUTH_TOKEN => DATA_TYPE_STRING,
|
||||
META_TLTI => DATA_TYPE_STRING
|
||||
];
|
||||
|
||||
public array $skipChecksForMeta = [
|
||||
BROKER_REQUEST_PING,
|
||||
BROKER_REQUEST_SCHEMA,
|
||||
BROKER_REQUEST_SHUTDOWN,
|
||||
BROKER_REQUEST_LOG,
|
||||
BROKER_REQUEST_MET,
|
||||
BROKER_REQUEST_MIGRATION
|
||||
];
|
||||
|
||||
public array /** @noinspection PhpUnused */ $allowedSessionStates = [
|
||||
STATUS_NEW,
|
||||
STATUS_PENDING,
|
||||
STATUS_ACTIVE
|
||||
];
|
||||
|
||||
public array $validClients = [
|
||||
CLIENT_SYSTEM,
|
||||
CLIENT_CSR,
|
||||
CLIENT_UNIT,
|
||||
CLIENT_AUDIT,
|
||||
CLIENT_CLIENT,
|
||||
CLIENT_API,
|
||||
CLIENT_API_USER
|
||||
];
|
||||
|
||||
// places (domains) where namaste lives
|
||||
public array /** @noinspection PhpUnused */ $validEnvironments = [
|
||||
ENV_ADMIN,
|
||||
ENV_APPSERVER, // aka: namaste
|
||||
ENV_SEGUNDO,
|
||||
ENV_TERCERO
|
||||
];
|
||||
|
||||
public bool $debug;
|
||||
public gacErrorLogger $logger;
|
||||
public array $config;
|
||||
public array $eventMessages;
|
||||
private string $res = 'META: ';
|
||||
|
||||
|
||||
/**
|
||||
* gacMeta constructor.
|
||||
*
|
||||
* sets public variables and, if explicitly requested, loads a logger class object.
|
||||
*
|
||||
* NOTES:
|
||||
* ------
|
||||
* about the XML configuration:
|
||||
*
|
||||
* The base-xml file configuration contains a new sub-section called: "meta"
|
||||
* Within this meta header, all of the valid clients are defined.
|
||||
* Within each client block, the required meta fields are listed and each meta field tag contains a boolean
|
||||
* value. The boolean setting is handled differently depending on the field as follows:
|
||||
*
|
||||
* clientID: required for all clients
|
||||
* eventGUID: required for all clients
|
||||
*
|
||||
* Fields that are not required assume the defaults.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param Boolean $_ll -- Load Logger (defaults to false)
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-09-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __construct(bool $_ll = false)
|
||||
{
|
||||
$this->debug = gasConfig::$settings[CONFIG_DEBUG];
|
||||
$this->config = [];
|
||||
$this->eventMessages = [];
|
||||
if ($_ll) {
|
||||
try {
|
||||
$this->logger = new gacErrorLogger();
|
||||
} catch (Throwable $t) {
|
||||
$msg = ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
$this->eventMessages[] = $msg;
|
||||
if (isset($this->logger) and $this->logger->available) {
|
||||
$this->logger->error($msg);
|
||||
} else {
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
$this->eventMessages = [];
|
||||
if (!empty(gasConfig::$settings[CONFIG_META])) {
|
||||
$this->config = gasConfig::$settings[CONFIG_META];
|
||||
} else {
|
||||
$msg = sprintf(INFO_LOC, basename(__FILE__), __LINE__, ERROR_CONFIG_404);
|
||||
$this->eventMessages[] = $msg;
|
||||
if (isset($this->logger) and $this->logger->available) $this->logger->fatal($msg);
|
||||
consoleLog($this->res, CON_SYSTEM, $msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* validateMetaPayload() -- protected method
|
||||
*
|
||||
* this protected method allows for validation of a meta-data payload submitted via the broker.
|
||||
*
|
||||
* the method ultimately returns a Boolean indicating whether or not ALL meta elements passed validation. In this
|
||||
* context, validation means we're validating that the meta fields are permitted and the defined types for each
|
||||
* field meet requirements.
|
||||
*
|
||||
* There is one input parameter to the method, described as follows:
|
||||
*
|
||||
* $_meta - the meta data payload, an associative array (vector) of key-value pairs
|
||||
*
|
||||
* requirements for success:
|
||||
* 1. that $_meta is an array and...
|
||||
* 2. that the $_meta keys are known...
|
||||
* 3. that all the $meta types are defined...
|
||||
* 4. that all of meta keys pass their respective validation requirements
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_meta -- associative vector containing meta payload from the broker event
|
||||
* @return bool -- true: all meta data was validated successfully, false: it was not
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-09-17 mks original coding
|
||||
* 07-30-18 mks CORE-774: PHP7.2 exception handling
|
||||
* 12-06-18 mks DB-55: pulled this code over from gasStatic to replace the local method (validateMeta -
|
||||
* which has been relocated to the deprecated folder) to provide a single, consistent
|
||||
* meta-data payload validation to the framework.
|
||||
* 06-02-20 mks ECI-108: support for SMAX API clients, fixed bug by eliminated $_results
|
||||
*/
|
||||
public function validateMetaPayload(&$_meta): bool
|
||||
{
|
||||
$badField = false;
|
||||
try {
|
||||
if (!is_array($_meta)) {
|
||||
$msg = ERROR_DATA_MISSING_ARRAY . STRING_META;
|
||||
$this->logger->data($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
return (false);
|
||||
}
|
||||
|
||||
foreach ($_meta as $key => &$value) {
|
||||
$badField = false;
|
||||
if (!array_key_exists($key, $this->fields)) {
|
||||
$msg = sprintf(NOTICE_META_DISCARD, $key);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->error($msg);
|
||||
unset($_meta[$key]);
|
||||
} else {
|
||||
switch ($key) {
|
||||
case META_SESSION_GUID :
|
||||
case META_USER_GUID :
|
||||
case META_BROKER_CHILD_GUID :
|
||||
case META_BROKER_GROOT :
|
||||
case META_EVENT_GUID :
|
||||
case META_SESSION_ID :
|
||||
case CLIENT_AUTH_TOKEN :
|
||||
if (!validateGUID($value)) {
|
||||
$msg = ERROR_INVALID_GUID . $key . COLON . $value;
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->error($msg);
|
||||
$badField = true;
|
||||
}
|
||||
break;
|
||||
case META_SESSION_IP :
|
||||
case META_CLIENT_IP :
|
||||
if (false === (filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6))) {
|
||||
$msg = ERROR_INVALID_IP . $key . COLON . $value;
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->error($msg);
|
||||
$badField = true;
|
||||
}
|
||||
break;
|
||||
case META_SKIP :
|
||||
case META_LIMIT :
|
||||
case META_LIMIT_OVERRIDE :
|
||||
case META_SESSION_DAEMON :
|
||||
case META_DONUT_FILTER :
|
||||
case META_SESSION_DATE :
|
||||
case META_SKIP_AUDIT :
|
||||
case META_AUDIT_EVENT :
|
||||
if (!is_numeric($value)) {
|
||||
$type = (is_integer($value)) ? DATA_TYPE_INTEGER : DATA_TYPE_DOUBLE;
|
||||
$msg = ERROR_DATA_INVALID_FORMAT . COLON . $key . ERROR_STUB_EXPECTING . $type;
|
||||
$msg .= ERROR_STUB_RECEIVED . gettype($value);
|
||||
$this->logger->error($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
$badField = true;
|
||||
}
|
||||
break;
|
||||
case META_DO_CACHE :
|
||||
if (!is_bool($value) and ($value != 0 and $value != 1)) {
|
||||
$msg = ERROR_DATA_INVALID_FORMAT . COLON . $key . ERROR_STUB_EXPECTING . DATA_TYPE_BOOL;
|
||||
$msg .= ERROR_STUB_RECEIVED . gettype($value);
|
||||
$this->logger->error($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
$badField = true;
|
||||
}
|
||||
break;
|
||||
case META_TEMPLATE :
|
||||
case META_SYSTEM_NOTES :
|
||||
case META_TARGET_ENV :
|
||||
case META_USER_INFO :
|
||||
case META_SESSION_EVENT :
|
||||
case META_SESSION_MISC :
|
||||
case META_SESSION_LOCATION :
|
||||
case META_TLTI :
|
||||
case META_BROKER_SERVICE :
|
||||
if (!is_string($value)) {
|
||||
$msg = ERROR_DATA_INVALID_FORMAT . COLON . $key . ERROR_STUB_EXPECTING . DATA_TYPE_STRING;
|
||||
$msg .= ERROR_STUB_RECEIVED . gettype($value);
|
||||
$this->logger->error($msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
$badField = true;
|
||||
}
|
||||
break;
|
||||
case META_CLIENT :
|
||||
if (!in_array($value, $this->validClients)) {
|
||||
$msg = ERROR_DATA_RANGE . COLON . $key . COLON . $value;
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->error($msg);
|
||||
$badField = true;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
$msg = sprintf(ERROR_UNK_META_TYPE, gettype($value), $key);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->data($msg);
|
||||
$badField = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($badField) {
|
||||
$this->logger->error(ERROR_DATA_META_REJECTED . $key);
|
||||
unset($_meta[$key]);
|
||||
}
|
||||
}
|
||||
return ($badField) ? false : true;
|
||||
} catch (TypeError $t) {
|
||||
consoleLog($this->res, CON_ERROR, $t->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* class destructor
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-09-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
//
|
||||
// destructor is registered shut-down function in constructor -- so any recovery
|
||||
// efforts should go in this method.
|
||||
}
|
||||
}
|
||||
3644
classes/gacMigrations.class.inc
Normal file
3644
classes/gacMigrations.class.inc
Normal file
File diff suppressed because it is too large
Load Diff
3218
classes/gacMongoDB.class.inc
Normal file
3218
classes/gacMongoDB.class.inc
Normal file
File diff suppressed because it is too large
Load Diff
3879
classes/gacPDO.class.inc
Normal file
3879
classes/gacPDO.class.inc
Normal file
File diff suppressed because it is too large
Load Diff
167
classes/gacSystemEvents.class.inc
Normal file
167
classes/gacSystemEvents.class.inc
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
/**
|
||||
* gacSystemEvents class
|
||||
* ---------------------
|
||||
* This class is for processing system events:
|
||||
* -- Broker Events (instantiation, forks, events, etc.)
|
||||
* -- Audit Events
|
||||
* -- Journaling Events
|
||||
*
|
||||
* This class instantiates it's own copy of gacAdminClientIn for publishing messages to the AdminIN broker. As such,
|
||||
* this class can be safely instantiated from any Namaste environment.
|
||||
*
|
||||
* @author mike@givvingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-16-17 mks CORE-500: initial coding
|
||||
* 03-02-18 mks CORE-680: deprecated trace logging
|
||||
* 08-02-18 mks CORE-774: PHP7.2 exception handling
|
||||
* 01-08-20 mks DB-150: PHP7.4 member type-casting
|
||||
*/
|
||||
|
||||
class gacSystemEvents extends gacMongoDB
|
||||
{
|
||||
private ?gacWorkQueueClient $aiClient;
|
||||
private string $res = 'cSEV: ';
|
||||
|
||||
|
||||
/**
|
||||
* gacSystemEvents constructor
|
||||
*
|
||||
* The constructor takes an optional parameter:
|
||||
*
|
||||
* $_meta -- the meta data as received by the broker event
|
||||
*
|
||||
* If the meta parameters is empty, the assumption is that this class was instantiated client-side
|
||||
* respective to the admin broker and we're preparing a publish event.
|
||||
*
|
||||
* The responsibilities of the constructor are basically to instantiate the class for pending requests.
|
||||
*
|
||||
* @author mike@givingassistant.com
|
||||
* @version 1.0
|
||||
*
|
||||
* @param null $_meta
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-17-17 mks CORE-500: original coding
|
||||
* 10-24-18 mks DB-57: mod for the meta data template override
|
||||
*
|
||||
*/
|
||||
public function __construct($_meta = null)
|
||||
{
|
||||
if (empty($_meta)) {
|
||||
$_meta = [
|
||||
META_TEMPLATE => TEMPLATE_CLASS_SYS_EVENTS,
|
||||
META_SESSION_DAEMON => 1
|
||||
];
|
||||
}
|
||||
// sometimes I forget to replace the class template in the meta data that initiated the system event...
|
||||
if ($_meta[META_TEMPLATE] != TEMPLATE_CLASS_SYS_EVENTS) $_meta[META_TEMPLATE] = TEMPLATE_CLASS_SYS_EVENTS;
|
||||
try {
|
||||
parent::__construct($_meta);
|
||||
} catch (Throwable $t) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
$msg = ERROR_THROWABLE_EXCEPTION . COLON . $t->getMessage();
|
||||
@handleExceptionMessaging($hdr, $msg, $this->eventMessages, true);
|
||||
$this->state = STATE_FRAMEWORK_FAIL;
|
||||
$this->status = false;
|
||||
return;
|
||||
}
|
||||
if (!$this->status) {
|
||||
$msg = ERROR_FAILED_TO_INSTANTIATE . STRING_CLASS_MONGO;
|
||||
if (isset($this->logger) and $this->logger->available)
|
||||
$this->logger->warn($msg);
|
||||
else
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
$this->eventMessages[] = $msg;
|
||||
return;
|
||||
}
|
||||
$this->aiClient = null;
|
||||
$this->class = get_class($this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fetchRecordBySessionGUID() -- public method
|
||||
*
|
||||
* This session-events class function requires a single input parameter:
|
||||
*
|
||||
* $_sessionGUID -- this is the session GUID, unique by definition, that we'll use to fetch the sys-event record
|
||||
*
|
||||
* The method assumes (because it was validated by the adminOut broker that called this method) that the GUID is valid.
|
||||
* We'll exec a schema-fetch based on the query build to filter by the session GUID. On success, the entire record will
|
||||
* populated in the current data object. Otherwise error messages and such.
|
||||
*
|
||||
* The function returns type void - success or failure can be tested by the class state/status.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_sessionGUID
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-20-20 mks DB-168: original coding
|
||||
*
|
||||
*/
|
||||
public function fetchRecordBySessionGUID(string $_sessionGUID):void
|
||||
{
|
||||
$query = [STRING_QUERY_DATA => [ SYSTEM_EVENT_FK_SESSION_GUID => [OPERAND_NULL => [OPERATOR_EQ => [$_sessionGUID]]]]];
|
||||
$this->_fetchRecords($query);
|
||||
if (!$this->status) {
|
||||
$this->eventMessages[] = ERROR_NOSQL_FETCH;
|
||||
consoleLog($this->res, CON_ERROR, sprintf(ERROR_MDB_FETCH_FAIL, TEMPLATE_CLASS_SYS_EVENTS) . SYSTEM_EVENT_FK_SESSION_GUID);
|
||||
} elseif ($this->count != 1) {
|
||||
$this->eventMessages[] = ERROR_FETCH;
|
||||
$this->logger->warn(sprintf(ERROR_DATA_RECORD_COUNT,1, $this->count));
|
||||
$this->logger->warn(json_encode($query));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- public method
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-17-15 mks CORE-500: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public method
|
||||
*
|
||||
* As of PHP 5.3.10, destructors are not run on shutdowns caused by fatal errors - since the destructor is
|
||||
* now registered in the constructor method, recovery and/or clean-up efforts should go into this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-17-15 mks CORE-500: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
}
|
||||
962
classes/gacUsers.class.inc
Normal file
962
classes/gacUsers.class.inc
Normal file
@@ -0,0 +1,962 @@
|
||||
<?php
|
||||
/**
|
||||
* Class gacUsers -- public GA class
|
||||
*
|
||||
* This is a Namaste::Admin data class for all things User.
|
||||
*
|
||||
* The user data lives on Namaste's Admin service. This class encompasses all the code for managing the user entity
|
||||
* including CRUD requests, and general user-type events such as login, logout, etc. The sister-table to this
|
||||
* collection is also a mongo collection living on Namaste::Admin and that's the session class.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-17-20 mks DB-168: original coding
|
||||
*
|
||||
*/
|
||||
|
||||
class gacUsers extends gacMongoDB
|
||||
{
|
||||
public string $res = 'cUSR: ';
|
||||
public ?array $securityConfig = null;
|
||||
public ?array $emailConfig = null;
|
||||
public ?array $sessionConfig = null;
|
||||
public string $myToken;
|
||||
public string $myAPIKey;
|
||||
public string $myUserType;
|
||||
|
||||
/**
|
||||
* gacUsers constructor.
|
||||
* @param array|null $_meta
|
||||
* @param string $_id
|
||||
*/
|
||||
public function __construct(?array $_meta = null, string $_id = '')
|
||||
{
|
||||
if (empty($_meta) or is_null($_meta)) {
|
||||
$_meta = [
|
||||
META_TEMPLATE => TEMPLATE_CLASS_USERS,
|
||||
META_SESSION_DAEMON => 1 // todo -- hook this up to something!
|
||||
];
|
||||
} elseif (!isset($_meta[META_TEMPLATE])) {
|
||||
// client didn't submit a template; let's fix that for them
|
||||
$_meta[META_TEMPLATE] = TEMPLATE_CLASS_USERS;
|
||||
} elseif ($_meta[META_TEMPLATE] != TEMPLATE_CLASS_USERS) {
|
||||
// there's a difference between unset and being set to the wrong class
|
||||
// todo -- system event for a hack attempt
|
||||
$_meta[META_TEMPLATE] = TEMPLATE_CLASS_USERS;
|
||||
}
|
||||
try {
|
||||
parent::__construct($_meta, $_id);
|
||||
if (!$this->isServiceLocal(ENV_TERCERO)) return;
|
||||
$this->myToken = '';
|
||||
$this->myAPIKey = '';
|
||||
$this->myUserType = '';
|
||||
$this->securityConfig = gasConfig::$settings[CONFIG_SECURITY];
|
||||
$this->emailConfig = gasConfig::$settings[CONFIG_EMAIL];
|
||||
$this->sessionConfig = gasConfig::$settings[CONFIG_SESSIONS];
|
||||
} catch (Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$this->eventMessages[] = ERROR_EXCEPTION;
|
||||
$msg = ERROR_FAILED_TO_INSTANTIATE . TEMPLATE_CLASS_USERS;
|
||||
$this->logger->fatal($hdr . $msg);
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
$this->state = STATE_FRAMEWORK_FAIL;
|
||||
$this->status = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* registerNewUser() -- public method
|
||||
*
|
||||
* This method is called when we're adding a new user to the system. The array of request data, as processed by
|
||||
* the broker, is the only input parameter.
|
||||
*
|
||||
* The function is of type void -- processing results are reflected in the class member settings.
|
||||
*
|
||||
* The method process the input data, ensuring that the minimally-required fields are present. The method then
|
||||
* performs the following validation checks and storage actions:
|
||||
*
|
||||
* 1. Validate the user's email address and domain
|
||||
* 2. Create the user record
|
||||
* 3. Create the user's session, linking the user record
|
||||
* 4. Create a System Event for the timer (expiry) event on Admin
|
||||
* 5. Publish an Admin request to register the session with AT(1)
|
||||
*
|
||||
* In the event of a system error, where we fail to instantiate a class or save a record, since we're working
|
||||
* with three different class objects in this method, and if the error is encountered in the session or system-
|
||||
* event classes, then we'll copy the eventMessages stack on that object over to the user object before
|
||||
* returning control to the calling client.
|
||||
*
|
||||
* Again, as there are no explicit or implicit returns via the parameters, the calling client has to check the
|
||||
* user-class data members for the results.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_data
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-14-20 mks DB-168: Original coding
|
||||
*
|
||||
*/
|
||||
public function registerNewUser(array $_data):void
|
||||
{
|
||||
$error = false;
|
||||
$this->state = STATE_VALIDATION_ERROR;
|
||||
$this->status = false;
|
||||
// we minimally need the user email and hashed password to proceed
|
||||
$minFields = [ USER_PII_EMAIL . $this->ext, USER_PASSWORD . $this->ext ]; // add fields as necessary
|
||||
// first, we're only going to allow the creation of one record per request...
|
||||
// ...so make sure $data is an array...
|
||||
if (!is_array($_data[BROKER_DATA])) {
|
||||
$this->eventMessages[] = ERROR_DATA_ARRAY_NOT_ARRAY;
|
||||
return;
|
||||
}
|
||||
// ...and that the array only has one record
|
||||
if (count($_data[BROKER_DATA]) != 1) {
|
||||
$this->eventMessages[] = sprintf(ERROR_DATA_ARRAY_COUNT, 1, STRING_DATA, count($_data[BROKER_DATA]));
|
||||
return;
|
||||
}
|
||||
$data = $_data[BROKER_DATA][0];
|
||||
// make sure the minimally-required fields are present:
|
||||
foreach ($minFields as $field) {
|
||||
if (!array_key_exists($field, $data)) {
|
||||
$this->eventMessages[] = ERROR_DATA_KEY_404 . $field;
|
||||
$error = true;
|
||||
}
|
||||
}
|
||||
if ($error) return;
|
||||
|
||||
// email validation: proper email, wblist, email does not already exist
|
||||
$this->validateUserEmail($data[USER_PII_EMAIL . $this->ext]);
|
||||
if (!$this->status) return;
|
||||
|
||||
// grab the partnerID, if it exists
|
||||
// (if no partner ID, the assumption is that we're creating an internal user)
|
||||
if (array_key_exists(CLIENT_AUTH_TOKEN, $_data[BROKER_META_DATA]))
|
||||
$data[USER_PARTNER_API_KEY] = $_data[BROKER_META_DATA][CLIENT_AUTH_TOKEN];
|
||||
|
||||
// create the new-user record and start gathering session data
|
||||
$this->_createRecord([$data]);
|
||||
if (!$this->status) return;
|
||||
|
||||
// calculate the session duration based on the XML configuration
|
||||
$duration = (gasConfig::$settings[CONFIG_SESSIONS][CONFIG_SESSIONS_DURATION_DAYS])
|
||||
? gasConfig::$settings[CONFIG_SESSIONS][CONFIG_SESSIONS_DURATION_DAYS] * NUMBER_ONE_DAY
|
||||
: gasConfig::$settings[CONFIG_SESSIONS][CONFIG_SESSIONS_DURATION_HOURS] * NUMBER_ONE_HOUR_SEC;
|
||||
|
||||
// build the session-record payload
|
||||
$sessionData = [
|
||||
SESSION_EXPIRES => time() + $duration,
|
||||
SESSION_DURATION => $duration,
|
||||
SESSION_LEVEL => SESSION_LEVEL_USER,
|
||||
SESSION_FK_USER => $this->getColumn(DB_TOKEN)
|
||||
// todo: other fields are legacy and we need to learn what to fill them with...
|
||||
];
|
||||
|
||||
// instantiate a new session object
|
||||
$metaCopy = $this->metaPayload;
|
||||
$metaCopy[META_TEMPLATE] = TEMPLATE_CLASS_SESSIONS;
|
||||
$errors = [];
|
||||
if (is_null($objSession = grabWidget($metaCopy, '', $errors))) {
|
||||
$this->eventMessages = [...$this->eventMessages, $errors];
|
||||
$this->state = STATE_FRAMEWORK_WARNING;
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$msg = ERROR_TEMPLATE_INSTANTIATE . $metaCopy[META_TEMPLATE];
|
||||
$this->logger->warn($hdr . $msg);
|
||||
consoleLog($this->res, CON_ERROR, $msg);
|
||||
return;
|
||||
}
|
||||
|
||||
// create the session record
|
||||
$objSession->_createRecord([$sessionData], DATA_USER);
|
||||
if (!$objSession->status) {
|
||||
$this->eventMessages = [ ...$this->eventMessages, ...$objSession->eventMessages ];
|
||||
if (is_object($objSession)) $objSession->__destruct();
|
||||
unset($objSession);
|
||||
$this->state = STATE_FRAMEWORK_FAIL;
|
||||
return;
|
||||
}
|
||||
// theses two values will be harvested back up at the broker level and used to create the return payload
|
||||
$this->sessionGUID = $objSession->getColumn(DB_TOKEN);
|
||||
$this->userGUID = $this->getColumn(DB_TOKEN);
|
||||
|
||||
// create the system-event data and publish the event to admin (or save locally if admin is local)
|
||||
$eventData = [
|
||||
SYSTEM_EVENT_NAME => EVENT_NAME_SESSION_EXPIRY,
|
||||
SYSTEM_EVENT_STATUS => STATUS_ACTIVE,
|
||||
SYSTEM_EVENT_TYPE => EVENT_TYPE_SESSION,
|
||||
SYSTEM_EVENT_FK_SESSION_GUID => $this->sessionGUID,
|
||||
SYSTEM_EVENT_FK_USER_GUID => $this->userGUID,
|
||||
SYSTEM_EVENT_CLASS => get_class($this),
|
||||
SYSTEM_EVENT_DURATION => $duration,
|
||||
SYSTEM_EVENT_BROKER_EVENT => $_data[BROKER_REQUEST],
|
||||
SYSTEM_EVENT_OGUID => $metaCopy[META_EVENT_GUID],
|
||||
SYSTEM_EVENT_CODE_LOC => basename(__FILE__) . AT . __LINE__,
|
||||
SYSTEM_EVENT_META_DATA => $metaCopy,
|
||||
SYSTEM_EVENT_NOTES => basename(__METHOD__)
|
||||
];
|
||||
|
||||
// invoke the function to publish the system event request and register the session with AT(1) on Admin:
|
||||
if (!postSystemEvent($eventData, $metaCopy[META_EVENT_GUID], $this->logger)) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, ERROR_MDB_SYS_EVENT_SAVE, $this->eventMessages, true);
|
||||
}
|
||||
|
||||
// call admin to fetch the token for the system event record we just created
|
||||
|
||||
// next, register the event with the admin broker AT(1) service
|
||||
$request = [
|
||||
BROKER_REQUEST => BROKER_REQUEST_NEW_SESSION,
|
||||
BROKER_DATA => [ SYSTEM_EVENT_DURATION => $duration ],
|
||||
BROKER_META_DATA => [
|
||||
META_TEMPLATE => TEMPLATE_CLASS_SYS_EVENTS,
|
||||
META_SESSION_GUID => $this->sessionGUID,
|
||||
META_CLIENT => CLIENT_SYSTEM
|
||||
]
|
||||
];
|
||||
|
||||
// get a copy of the record we just created
|
||||
// $dataSystemEvent = $objSession->getData();
|
||||
// $dataSystemEvent = $dataSystemEvent[0];
|
||||
|
||||
// create the broker client and publish the BROKER_REQUEST_NEW_SESSION event to AdminInBroker to register
|
||||
// the session expiry with AT(1)
|
||||
/** @var gacWorkQueueClient $tmpObj */
|
||||
$tmpObj = new gacWorkQueueClient(basename(__METHOD__) . AT . __LINE__);
|
||||
if (is_null($tmpObj) or !$tmpObj->status) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$msg = ERROR_TEMPLATE_INSTANTIATE . sprintf(ERROR_BROKER_CLIENT_INSTANTIATION, STRING_WORK_QUEUE_CLIENT);
|
||||
@handleExceptionMessaging($hdr, $msg, $this->eventMessages, true);
|
||||
return;
|
||||
}
|
||||
// fire-n-forget queue
|
||||
$tmpObj->call(gzcompress(json_encode($request)));
|
||||
|
||||
// todo: validation email
|
||||
|
||||
// clean-up and return a success condition
|
||||
if (is_object($objSession)) $objSession->__destruct();
|
||||
if (is_object($tmpObj)) $tmpObj->__destruct();
|
||||
unset($objSession, $tmpObj);
|
||||
$this->state = STATE_SUCCESS;
|
||||
$this->status = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* validateUserEmail() -- public method
|
||||
*
|
||||
* this method is the single entry-point for all email checks.
|
||||
*
|
||||
* this method checks a submitted email address:
|
||||
*
|
||||
* 1. sanitize the email removing invalid characters
|
||||
* 2. validate that the email is in the correct format
|
||||
* 3. validate the email domain
|
||||
* 4. validate the the email is unique
|
||||
* 5. validate against the WBL list
|
||||
*
|
||||
* If case 1 or case 2 fails, then a STATE_VALIDATION_ERROR is returned -- the email address itself is invalid
|
||||
*
|
||||
* Next, check to see if the email address exists in the database. We're going to check both the primary
|
||||
* and alternate email addresses.
|
||||
*
|
||||
* if the query comes back success and the data count is true, that's implicit indication that the
|
||||
* email is in-use. What we want to do is make an additional check on the status of the email.
|
||||
*
|
||||
* If the status is false, (from the query), then we want to check for a 404-state -- indicating that no records
|
||||
* were found for that email and it's ok to use.
|
||||
*
|
||||
* any other state/status combination defaults to a framework warning and a check-logs diagnostic is generated.
|
||||
*
|
||||
* Return States:
|
||||
* --------------
|
||||
* STATE_SUCCESS -- email address is valid, not already in-use, and is white-listed
|
||||
* STATE_NOT_WHITE_LIST -- email does not appear on the white list and white-list checks are enabled
|
||||
* STATE_BLACK_LIST -- email has been black-listed
|
||||
* STATE_VALIDATION_ERROR -- email address as submitted was empty or malformed
|
||||
* STATE_ALREADY_EXISTS -- email address is in-use and cannot be reused
|
||||
* STATE_MAIL_FAIL -- processing error within the framework
|
||||
* STATE_FRAMEWORK_WARNING -- some random bad thing happened and needs investigation
|
||||
*
|
||||
* Note that the $_email parameter is a call-by-reference who's contents may be altered by this method.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_email -- the email to validate/check
|
||||
* @param Boolean $_skipCheck -- if set to true, skip email-already-exists check (for logins)
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-18-20 mks DB-168: original coding
|
||||
*
|
||||
*/
|
||||
public function validateUserEmail(string &$_email, bool $_skipCheck = false):void
|
||||
{
|
||||
$oldData = null;
|
||||
$whiteList = true;
|
||||
$blackList = true;
|
||||
$oldCount = 0;
|
||||
$this->state = STATE_VALIDATION_ERROR;
|
||||
$this->status = false;
|
||||
$backup = false;
|
||||
|
||||
if (empty($this->metaPayload)) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$this->logger->warn($hdr . ERROR_DATA_META_404);
|
||||
$this->eventMessages[] = ERROR_DATA_META_404;
|
||||
$this->status = false;
|
||||
$this->state = STATE_META_ERROR;
|
||||
return;
|
||||
}
|
||||
$metaCopy = $this->metaPayload;
|
||||
$metaCopy[META_TEMPLATE] = TEMPLATE_CLASS_WBL;
|
||||
|
||||
if ($this->count and !empty($this->data)) {
|
||||
$oldData = $this->getData();
|
||||
$oldCount = $this->count;
|
||||
$this->data = [];
|
||||
$this->count = 0;
|
||||
$backup = true;
|
||||
}
|
||||
|
||||
// ensure we have input parameters
|
||||
if (empty($_email)) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$msg = ERROR_DATA_KEY_404 . USER_PII_EMAIL;
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->data($hdr . $msg);
|
||||
if ($backup) {
|
||||
$this->count = $oldCount;
|
||||
$this->data = $oldData;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (empty($this->emailConfig) or !is_array($this->emailConfig)) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$msg = ERROR_CONFIG_RESOURCE_404 . RESOURCE_EMAIL;
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->data($hdr . $msg);
|
||||
if ($backup) {
|
||||
$this->count = $oldCount;
|
||||
$this->data = $oldData;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// force the user email to lowercase
|
||||
$_email = trim(mb_strtolower($_email));
|
||||
|
||||
// validate the email and email domain
|
||||
if (!checkEmailAndDomain($_email)) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$msg = ERROR_DIAG_EMAIL_MALFORMED . COLON . $_email;
|
||||
@handleExceptionMessaging($hdr, $msg, $this->eventMessages);
|
||||
$this->state = STATE_MAIL_FAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
// check for duplicate emails
|
||||
if (!$_skipCheck) {
|
||||
$state = $this->emailSearch($_email);
|
||||
switch ($state) {
|
||||
case STATE_FRAMEWORK_WARNING :
|
||||
case STATE_ALREADY_EXISTS :
|
||||
$this->state = $state;
|
||||
$this->status = false;
|
||||
if ($backup) {
|
||||
$this->count = $oldCount;
|
||||
$this->data = $oldData;
|
||||
}
|
||||
return;
|
||||
break;
|
||||
case STATE_DOES_NOT_EXIST :
|
||||
// do nothing: optimal return
|
||||
break;
|
||||
default :
|
||||
$this->status = false;
|
||||
$msg = ERROR_UNKNOWN_STATE . $state;
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->warn($msg);
|
||||
if ($backup) {
|
||||
$this->count = $oldCount;
|
||||
$this->data = $oldData;
|
||||
}
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if either whitelisting or blacklisting are enabled for the client, then check the wbl
|
||||
if ($whiteList or $blackList) {
|
||||
try {
|
||||
$this->checkWBL($_email);
|
||||
if ($this->debug) {
|
||||
$this->logger->debug('email checked: ' . $_email);
|
||||
$this->logger->debug('objWBL state: ' . $this->state);
|
||||
$this->logger->debug('objWBL status: ' . (($this->status) ? STRING_TRUE : STRING_FALSE));
|
||||
}
|
||||
} catch (Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$msg = $t->getMessage();
|
||||
$this->eventMessages[] = ERROR_EXCEPTION;
|
||||
@handleExceptionMessaging($hdr, $msg, $this->eventMessages);
|
||||
$this->eventMessages = array_pop($this->eventMessages);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
$this->state = STATE_SUCCESS;
|
||||
$this->status = true;
|
||||
}
|
||||
// reset the current class data
|
||||
if ($backup) {
|
||||
$this->count = $oldCount;
|
||||
$this->data = $oldData;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* emailSearch() -- private method
|
||||
*
|
||||
* this method accepts an email address as it's only input parameter and generates a query to check to
|
||||
* see if the email already exists in the user collection.
|
||||
*
|
||||
* the method returns a state (string) determined by the following conditions:
|
||||
*
|
||||
* STATE_FRAMEWORK_WARNING - processing or db error
|
||||
* STATE_ALREADY_EXISTS - email is already in-use in the db
|
||||
* STATE_DOES_NOT_EXIST - email is not in-use (desired return)
|
||||
*
|
||||
* The calling client should evaluate the return state accordingly as this method does not change the class
|
||||
* state/status params.
|
||||
*
|
||||
* The calling client should also reset the data payload as, if a record is found, then the found record will
|
||||
* be added to the current data member.
|
||||
*
|
||||
* This method was written to reduce the code footprint of the validateUserEmail method.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_email
|
||||
* @return string
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-18-20 mks DB-169: original coding
|
||||
*
|
||||
*/
|
||||
private function emailSearch(string $_email): string
|
||||
{
|
||||
$return = STATE_FRAMEWORK_WARNING;
|
||||
// check if tercero is not a "local" service
|
||||
if (!gasConfig::$settings[ENV_TERCERO][CONFIG_IS_LOCAL]) return $return;
|
||||
|
||||
// set-up the email query
|
||||
$query = [
|
||||
STRING_QUERY_DATA => [
|
||||
USER_PII_EMAIL => [ OPERAND_NULL => [ OPERATOR_EQ => [ $_email ]]],
|
||||
USER_PII_SECONDARY_EMAIL => [ OPERAND_NULL => [ OPERATOR_EQ => [ $_email]]],
|
||||
OPERAND_OR => null
|
||||
],
|
||||
STRING_RETURN_DATA => [ CM_TOKEN ]
|
||||
];
|
||||
// query the db
|
||||
$this->_fetchRecords($query);
|
||||
switch ($this->status) {
|
||||
case true :
|
||||
if ($this->count) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$msg = sprintf(ERROR_EMAIL_DUPLICATE, $_email);
|
||||
$this->eventMessages[] = $msg;
|
||||
$this->logger->data($hdr . $msg);
|
||||
$return = STATE_ALREADY_EXISTS;
|
||||
} elseif ($this->state == STATE_NOT_FOUND) {
|
||||
return STATE_DOES_NOT_EXIST;
|
||||
}
|
||||
break;
|
||||
case false :
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$this->logger->warn($hdr . $this->strQuery);
|
||||
$this->logger->warn($hdr . ERROR_CHECK_LOGS);
|
||||
$this->eventMessages[] = ERROR_CHECK_LOGS;
|
||||
break;
|
||||
}
|
||||
return($return);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* checkWBL() -- public method
|
||||
*
|
||||
* this method checks the submitted email and domain against the White/Black list data.
|
||||
*
|
||||
* there is but one input parameter required for the method:
|
||||
*
|
||||
* $_email -- a string containing the email to be evaluated
|
||||
*
|
||||
* the method begins by looping through the email - the address is processed by first evaluating the
|
||||
* entire email (for a match in the WBL table) and, if not found, then we continue with the domain-part of
|
||||
* the email (right-side of the '@') and continue to remove sub-domains until we get to the TLD. If we
|
||||
* get to the TLD, then the user is neither black-listed or white-listed.
|
||||
*
|
||||
* if we get a domain match, or if we match the entire email, then we look at the WBL record "type" (a boolean)
|
||||
* to determine if the WBL record is a black (false) or white (true) listed email.
|
||||
*
|
||||
* The following states are assigned to the class under the following:
|
||||
*
|
||||
* STATE_DB_ERROR -- the WBL record was found, but no value was stored in the "type_wbl" column
|
||||
* -- more than one WBL record was found for the email/domain
|
||||
* -- the search query failed to execute successfully
|
||||
* STATE_SUCCESS -- the email/domain is white-listed
|
||||
* STATE_BLACK_LIST -- the email/domain is black-listed
|
||||
* STATE_NOT_FOUND -- the email/domain is neither white-listed or black-listed, or wbl is disabled
|
||||
*
|
||||
* the method return is the class STATE variable which should be evaluated by the calling client upon return.
|
||||
*
|
||||
* Programmer's Notes:
|
||||
* -------------------
|
||||
* This method is a member of the user class, as opposed to the WBList class, for efficiency - we can check a user's
|
||||
* email in this class without resorting to instantiating another data class (WBList) for the check.
|
||||
*
|
||||
* PENDING WORK:
|
||||
* -------------
|
||||
* todo: code the security event when a black-listed return is encountered
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_email
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-19-20 mks DB-168: original coding
|
||||
*
|
||||
*/
|
||||
public function checkWBL(string $_email):void
|
||||
{
|
||||
// lvar init
|
||||
$wblState = null;
|
||||
$emailBits = explode(AT, $_email);
|
||||
$domain = $emailBits[1];
|
||||
$diminishingDomain = $domain;
|
||||
$method = basename(__METHOD__);
|
||||
$domainBits = explode(DOT, $domain);
|
||||
$counter = 0;
|
||||
$errorList = [];
|
||||
$this->status = false;
|
||||
$this->state = STATE_VALIDATION_ERROR;
|
||||
$blEnabled = boolval(gasConfig::$settings[CONFIG_SECURITY][CONFIG_SECURITY_BANNED_LIST]);
|
||||
$wlEnabled = boolval(gasConfig::$settings[CONFIG_SECURITY][CONFIG_SECURITY_RESTRICTED_LIST]);
|
||||
|
||||
// return immediately if wbl is disabled system-wide
|
||||
if (!$blEnabled and !$wlEnabled) {
|
||||
$this->state = STATE_NOT_SUPPORTED;
|
||||
$this->status = true;
|
||||
return;
|
||||
}
|
||||
|
||||
$tmpMeta = $this->metaPayload;
|
||||
$tmpMeta[META_TEMPLATE] = TEMPLATE_CLASS_WBL;
|
||||
/** @var gacMongoDB $widget */
|
||||
if (is_null($widget = grabWidget($tmpMeta, '', $errorList))) {
|
||||
foreach ($errorList as $error)
|
||||
$this->logger->error($error);
|
||||
$this->eventMessages = [...$this->eventMessages, ...$errorList];
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* we start with all of the domain. If there are sub-domains embedded in the domain,
|
||||
* start by searching with the left-most sub-domain and each iteration, remove a sub-domain
|
||||
* until we either find an entry in the collection, or we run out of domain.
|
||||
*
|
||||
* This technique allows us to validate an email submitted such as: mike@backend.engineering.givva.com
|
||||
* to one of the following:
|
||||
*
|
||||
* 1. mike@backend.engineering.givva.com
|
||||
* 2. mike@engineering.givva.com
|
||||
* 3. mike@givva.com
|
||||
*
|
||||
*/
|
||||
|
||||
// first, check to see if the email USER is explicitly listed in the WBL collection:
|
||||
$query = [ USER_PII_EMAIL => [ OPERAND_NULL => [ OPERATOR_EQ => [ $_email ]]]];
|
||||
$widget->_fetchRecords([STRING_QUERY_DATA => $query]);
|
||||
if ($widget->status and $widget->count == 1) {
|
||||
// email is either white or black-listed
|
||||
if (is_null($wbl = $widget->getColumn(MONGO_WBL_TYPE))) {
|
||||
// edge case: there is no WBL Type setting so ... this is a system event! Why would a user be listed
|
||||
// in the table but not have a setting?!? Database error...
|
||||
// todo: system event for incomplete data record found in the database
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
$this->state = STATE_DATA_ERROR;
|
||||
$this->eventMessages[] = ERROR_GENERIC_CUSTOMER;
|
||||
$this->logger->warn($hdr . ERROR_BAD_DATA_RECORD . 'wbl-type is not populated');
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
return;
|
||||
}
|
||||
// ... otherwise, if there we found a record for the email address, check to see if it's a white or black-listed entry
|
||||
$this->state = (boolval($wbl)) ? STATE_SUCCESS : STATE_BLACK_LIST;
|
||||
$this->status = ($this->state == STATE_SUCCESS) ? true : false;
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
return;
|
||||
} elseif ($widget->status and $widget->state == STATE_NOT_FOUND) {
|
||||
// record was not found - which is not a problem unless whitelisting is enabled
|
||||
$this->status = true;
|
||||
$this->state = ($wlEnabled) ? STATE_NOT_WHITE_LIST : STATE_SUCCESS;
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
return;
|
||||
} elseif ($widget->status and $widget->count > 1 and $widget->state != STATE_NOT_FOUND) {
|
||||
// more than one record was found
|
||||
$msg = sprintf(MONGO_FAILED_TOO_MANY_RECS, 1) . $widget->count;
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $msg, $this->eventMessages, true);
|
||||
$this->state = STATE_DB_ERROR;
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
return;
|
||||
} elseif (!$widget->status) {
|
||||
// query fail
|
||||
$this->eventMessages[] = ERROR_CHECK_LOGS;
|
||||
$this->state = STATE_FAIL;
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
return;
|
||||
}
|
||||
|
||||
// process the email DOMAIN until we find an entry in the wbl table or we run out of domain
|
||||
for ($index = count($domainBits); $index > 1; $index--) {
|
||||
$query = [USER_PII_EMAIL => [OPERAND_NULL => [OPERATOR_EQ => [(AT . $diminishingDomain)]]]];
|
||||
$widget->_fetchRecords([STRING_QUERY_DATA => $query]);
|
||||
$wblState = $widget->getColumn(MONGO_WBL_TYPE);
|
||||
if ($widget->status and $widget->count == 1) {
|
||||
// a wbl record exists for the domain
|
||||
if (false === boolval($wblState)) {
|
||||
// domain has been explicitly black listed
|
||||
$this->state = STATE_BLACK_LIST;
|
||||
$this->status = true;
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
return;
|
||||
// todo -- system event
|
||||
} elseif (true === boolval($wblState)) {
|
||||
// domain has been explicitly white listed
|
||||
$this->state = STATE_SUCCESS;
|
||||
$this->status = true;
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
return;
|
||||
} elseif (is_null($wblState)) {
|
||||
// record exists but type is not defined
|
||||
$this->state = STATE_DATA_ERROR;
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
return;
|
||||
}
|
||||
} elseif ($widget->status and $widget->state == STATE_NOT_FOUND) {
|
||||
// no records returned -- shrink the domain
|
||||
$diminishingDomain = ltrim($diminishingDomain, ($domainBits[$counter++] . DOT));
|
||||
}
|
||||
}
|
||||
// if we're done processing the domain and we land here, then the check the $wblType for null
|
||||
if (is_null($wblState) and $wlEnabled) {
|
||||
// none of the domain was found and white-listing is enabled
|
||||
$this->state = STATE_NOT_WHITE_LIST;
|
||||
$this->status = false;
|
||||
} else {
|
||||
// wl is not enabled and no wbl record was found for any of the domain
|
||||
$this->state = STATE_SUCCESS;
|
||||
$this->status = true;
|
||||
}
|
||||
if (is_object($widget)) $widget->__destruct();
|
||||
unset($widget);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hashText() -- protected method
|
||||
*
|
||||
* This method requires a single input parameter, the text to be hashed:
|
||||
*
|
||||
* $_text -- string containing the text to be hashed
|
||||
*
|
||||
* The method will check the XML configuration for the hashing algorithm to use. If the security section was
|
||||
* not properly loaded during instantiation, or if the calling client did not provide input text, then an error
|
||||
* message will be generated and a null value returned.
|
||||
*
|
||||
* Otherwise, we'll use the password_hash() function to generate a hash of the request text. If the function
|
||||
* returns a Boolean(false), then we'll generate an error message and return a null to the requesting client.
|
||||
*
|
||||
* Otherwise, return the hashed string.
|
||||
*
|
||||
* Programmer's Notes:
|
||||
* -------------------
|
||||
* I've marked this as protected so that it cannot be invoked (generate a hash) outside of the user instantiation
|
||||
* stack. This is to limit access to the Namaste hashing algorithm to only the user class.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_text
|
||||
* @return string|null
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-31-20 mks DB-168: original coding
|
||||
*
|
||||
*/
|
||||
protected function hashText(string $_text):?string
|
||||
{
|
||||
$method = basename(__METHOD__);
|
||||
if (empty($this->securityConfig)) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
$msg = ERROR_CONFIG_RESOURCE_404 . CONFIG_SECURITY;
|
||||
@handleExceptionMessaging($hdr, $msg, $this->eventMessages);
|
||||
return null;
|
||||
}
|
||||
if (empty($_text)) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
$msg = ERROR_DATA_404;
|
||||
@handleExceptionMessaging($hdr, $msg, $this->eventMessages);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
// if set, pull the hash algorithm from namaste config, o/w set to default and call hash function
|
||||
$hash = password_hash($_text, (!isset($this->securityConfig[CONFIG_SECURITY_HASH_ALGO])) ? PASSWORD_ARGON2I : $this->securityConfig[CONFIG_SECURITY_HASH_ALGO]);
|
||||
if (false === $hash) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
$msg = ERROR_PASSWORD_HASH_GENERATION_FAILED;
|
||||
@handleExceptionMessaging($hdr, $msg, $this->eventMessages);
|
||||
return null;
|
||||
}
|
||||
return $hash;
|
||||
} catch (TypeError | Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $this->eventMessages);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hashFetch() -- private method
|
||||
*
|
||||
* This method has two input parameters:
|
||||
*
|
||||
* $_searchValue - this should be either a 36-character GUID value, or an email address
|
||||
* $_retData -- call-by-reference parameter that, if submitted, will contain the user's type and api-key in
|
||||
* addition to the password hash and account token
|
||||
*
|
||||
* We'll test to see if the input value is either a GUID or an email address and will structure the query
|
||||
* to match. If the searchValue is not either, then generate error messages, return a null, and exit.
|
||||
*
|
||||
* If the query generated an error, or returns a not found, we'll generate appropriate messaging and return
|
||||
* a null value to the calling client preserving class state/status and query results data.
|
||||
*
|
||||
* Otherwise, we'll return the password hash to the calling client.
|
||||
*
|
||||
* Programmer's Notes:
|
||||
* -------------------
|
||||
* This function is private so as to limit access to the user table for the purposes of accessing the hash key
|
||||
* to this class only.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string|null $_searchValue -- the email or guid value of the target record
|
||||
* @param array|null $_retData -- call by reference param to return additional record data
|
||||
* @return string|null
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-31-20 mks DB-168: original coding
|
||||
*
|
||||
*/
|
||||
private function hashFetch(?string $_searchValue = null, ?array &$_retData = null):?string
|
||||
{
|
||||
$method = basename(__METHOD__);
|
||||
// search key can be either a token or an email address - figure out which
|
||||
if (empty($_searchValue)) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
$msg = ERROR_PARAM_404 . STRING_TOKEN;
|
||||
@handleExceptionMessaging($hdr, $msg, $this->eventMessages);
|
||||
return null;
|
||||
} elseif (validateGUID($_searchValue))
|
||||
$searchKey = STRING_TOKEN;
|
||||
elseif (false !== filter_var($_searchValue, FILTER_VALIDATE_EMAIL))
|
||||
$searchKey = USER_PII_EMAIL;
|
||||
else {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
$msg = ERROR_DATA_INVALID_KEY . $_searchValue;
|
||||
@handleExceptionMessaging($hdr, $msg, $this->eventMessages);
|
||||
return null;
|
||||
}
|
||||
|
||||
// build the query to fetch the user's hash based on the record token
|
||||
$query = [
|
||||
$searchKey => [ STRING_TOKEN => [ OPERAND_NULL => [ OPERATOR_EQ => [ $_searchValue]]]],
|
||||
STRING_RETURN_DATA => [ USER_PASSWORD, USER_TYPE, USER_PARTNER_API_KEY, DB_STATUS ]
|
||||
];
|
||||
$this->_fetchRecords($query);
|
||||
if (!$this->status) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
$msg = sprintf(ERROR_MDB_QUERY_FAIL, STRING_SEARCH);
|
||||
@handleExceptionMessaging($hdr, $msg, $this->eventMessages);
|
||||
return null;
|
||||
} elseif ($this->state == STATE_NOT_FOUND) {
|
||||
$this->eventMessages[] = ERROR_DATA_404;
|
||||
return null;
|
||||
}
|
||||
// class data gets reset on successful search and return
|
||||
$_retData = $this->getData();
|
||||
$_retData = $_retData[0];
|
||||
if (isset($_retData[STRING_PASSWORD . $this->ext])) unset($_retData[STRING_PASSWORD . $this->ext]);
|
||||
$hash = $this->getColumn(USER_PASSWORD);
|
||||
$this->removeData();
|
||||
return $hash;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hashCheck() -- public function
|
||||
*
|
||||
* This is the public function, access point, for validating a user's password hash. The method has the
|
||||
* following input parameters to the method:
|
||||
*
|
||||
* $_searchValue -- this can be either a GUID or an email address and will be used as search key
|
||||
* $_hashText -- this is the hash text as generated by the client that we'll compare to the stored hash
|
||||
*
|
||||
* There are no explicit parameters returned. However, we make use of the class state/status members to pass-back
|
||||
* the state and status of the request which should be processed by the calling client.
|
||||
* If either parameter is passed empty, then generate messaging and return.
|
||||
*
|
||||
* The method invokes the hashFetch() method, passing in the search-value to fetch the password hash from the
|
||||
* database record and, in the same line, invokes the password_verify() function to validate the user
|
||||
* submitted pre-hash value against the stored hash.
|
||||
*
|
||||
* Programmer's Notes:
|
||||
* -------------------
|
||||
* Anytime you want to add layered-validation, like ensuring that partner account belongs to a partner, you'll want
|
||||
* to add those checks to this method.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_searchValue
|
||||
* @param $_hashText
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-31-20 mks DB-168: Original coding
|
||||
*
|
||||
*/
|
||||
public function hashCheck(string $_searchValue, $_hashText):void
|
||||
{
|
||||
$this->status = false;
|
||||
$this->state = STATE_AUTH_ERROR;
|
||||
$userData = null;
|
||||
$method = basename(__METHOD__);
|
||||
|
||||
if (empty($_searchValue) or empty($_hashText)) {
|
||||
$this->eventMessages[] = ERROR_DATA_404;
|
||||
return;
|
||||
}
|
||||
if (password_verify($_hashText, $this->hashFetch($_searchValue, $userData))) {
|
||||
// if the hash verification was successful...
|
||||
// check the account status for non-active states:
|
||||
if ($userData[DB_STATUS . $this->ext] != STATUS_ACTIVE) {
|
||||
switch ($userData[DB_STATUS . $this->ext]) {
|
||||
case STATUS_LOCKED :
|
||||
case STATUS_CLOSED :
|
||||
case STATUS_SUSPENDED :
|
||||
case STATUS_REVOKED :
|
||||
case STATUS_INACTIVE :
|
||||
// account needs CSR intervention
|
||||
break;
|
||||
case STATUS_ABANDONED :
|
||||
// account needs to have status updated and password change forced
|
||||
|
||||
break;
|
||||
case STATUS_PENDING :
|
||||
// account needs to validate their email
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isset($userData[USER_TYPE . $this->ext]) and ($userData[USER_TYPE . $this->ext] == USER_TYPE_PARTNER)) {
|
||||
// ...and we have a userType and that type is equal to "partner"...
|
||||
if (isset($userData[USER_PARTNER_API_KEY . $this->ext]) and validateGUID($userData[USER_PARTNER_API_KEY . $this->ext])) {
|
||||
// ...and we have an partner API key in the user record...
|
||||
if (isset($this->metaPayload[CLIENT_AUTH_TOKEN])) {
|
||||
// ...and we have the XPI-Key set in the meta payload...
|
||||
if ($this->metaPayload[CLIENT_AUTH_TOKEN] == $userData[USER_PARTNER_API_KEY . $this->ext]) {
|
||||
// ...and the meta-payload X-API-Key matches the API-Key stored in the user record...
|
||||
// then we have a successful partner-user login!
|
||||
$this->myAPIKey = $userData[USER_PARTNER_API_KEY . $this->ext];
|
||||
$this->myUserType = $userData[USER_TYPE . $this->ext];
|
||||
if (isset($userData[STRING_TOKEN . $this->ext]))
|
||||
$this->myToken = $userData[STRING_TOKEN . $this->ext];
|
||||
$this->state = STATE_SUCCESS;
|
||||
$this->status = true;
|
||||
return;
|
||||
} else {
|
||||
// client auth token in meta payload does not match xpi-key in user record
|
||||
$this->eventMessages[] = ERROR_PARTNER_API_KEY_MISMATCH;
|
||||
return;
|
||||
// todo security system event
|
||||
}
|
||||
} else {
|
||||
// Event request was from a partner, but user is not associated with a partner account
|
||||
$this->eventMessages[] = ERROR_PARTNER_USER_NOT_MEMBER;
|
||||
// todo security system event
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// either the api-key is not set or is an invalid guid (and the user is partner'd)
|
||||
if (!isset($userData[USER_PARTNER_API_KEY . $this->ext])) {
|
||||
// partner key was not set in the user record
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
$this->logger->warn($hdr . ERROR_PARTNER_USER_NOT_REGISTERED);
|
||||
$this->eventMessages[] = ERROR_PARTNER_USER_NOT_MEMBER;
|
||||
$this->state = STATE_DB_ERROR;
|
||||
return;
|
||||
} else {
|
||||
// the partner key guid stored in the user record is bad
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
$this->eventMessages[] = ERROR_PARTNER_USER_DATA;
|
||||
$msg = sprintf(ERROR_PARTNER_USER_HAS_BAD_GUID, $userData[USER_PARTNER_API_KEY . $this->ext], USER_PARTNER_API_KEY);
|
||||
$this->logger->warn($hdr . $msg);
|
||||
$this->logger->warn(ERROR_INVALID_GUID . $userData[USER_PARTNER_API_KEY . $this->ext]);
|
||||
$this->state = STATE_DATA_ERROR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} // END - check to see if user belongs to a partner
|
||||
} else {
|
||||
$this->eventMessages[] = ERROR_PASSWORD_MISMATCH;
|
||||
}
|
||||
}
|
||||
}
|
||||
169
classes/gacWorkQueueClient.class.inc
Normal file
169
classes/gacWorkQueueClient.class.inc
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* this class is used when we want to publish a request to the AdminIn broker. The class wraps all of the
|
||||
* RabbitMQ initialization and communication work so you don't have to. Especially useful for unit testing.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks original coding
|
||||
* 07-07-17 mks CORE-463: updated for async logging (appserver posting log events to admin server)
|
||||
* 07-31-18 mks CORE-774: PHP7.2 exception handling
|
||||
* 01-29-20 mks DB-144: PHP7.4 support
|
||||
* 10-15-20 mks DB-168: renamed, supports all namaste work queues (adminBrokerIn and sBroker)
|
||||
*
|
||||
*/
|
||||
|
||||
use PhpAmqpLib\Channel\AMQPChannel;
|
||||
use PhpAmqpLib\Exception\AMQPRuntimeException;
|
||||
use PhpAmqpLib\Exception\AMQPTimeoutException;
|
||||
use PhpAmqpLib\Message\AMQPMessage;
|
||||
|
||||
class gacWorkQueueClient
|
||||
{
|
||||
private object $rabbitConnection; // actually contains AMQPStreamConnection type but the API declares object|null
|
||||
private ?AMQPChannel $rabbitChannel = null;
|
||||
private ?string $rabbitCallbackQueue;
|
||||
private ?string $rabbitResponse;
|
||||
private string $rabbitCorrelationID;
|
||||
private string $queueName;
|
||||
|
||||
public bool $status;
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* this is the constructor for the class. it requests an admin resource from the resource manager and declares
|
||||
* a client-side connection to the service.
|
||||
*
|
||||
* there is an optional input parameter -- $_fw (from-where) that inserts a string into the queue label allowing
|
||||
* easy identification of the requesting source.
|
||||
*
|
||||
* the method returns no values. It only sets the class' status member variable, a Boolean, on success or fail,
|
||||
* accordingly.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* @param $_fw - "from where" - tweaks queue label to identify request origin
|
||||
* @param $_which - which fire-n-forget broker queue to attache to (default is adminIn)
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks original coding
|
||||
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
||||
* 05-31-18 mks CORE-1011: update for new XML broker services configuration
|
||||
* 09-19-19 mks DB-136: improved exception handling
|
||||
* 10-02-20 mks DB-168: support for (new) session broker (also fire-n-forget), removed callback method
|
||||
*
|
||||
*/
|
||||
public function __construct(string $_fw = __METHOD__ . AT . __LINE__, string $_which = BROKER_QUEUE_AI)
|
||||
{
|
||||
register_shutdown_function(array($this, STRING_DESTRUCTOR));
|
||||
$this->status = false;
|
||||
|
||||
switch ($_which) {
|
||||
case BROKER_QUEUE_AI :
|
||||
$resource = RESOURCE_ADMIN;
|
||||
$queue = BROKER_QUEUE_AI;
|
||||
$labelClient = 'gacAdminInClient<';
|
||||
break;
|
||||
case BROKER_QUEUE_S :
|
||||
$resource = RESOURCE_TERCERO;
|
||||
$queue = BROKER_QUEUE_S;
|
||||
$labelClient = 'gacSessionClient<';
|
||||
break;
|
||||
default :
|
||||
consoleLog('cACI: ', CON_ERROR, ERROR_CONFIG_RESOURCE_404 . $_which);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
$this->queueName = gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG] . $queue;
|
||||
try {
|
||||
$this->rabbitConnection = gasResourceManager::fetchResource($resource);
|
||||
if (is_null($this->rabbitConnection)) return;
|
||||
$this->rabbitChannel = $this->rabbitConnection->channel();
|
||||
$label = uniqid($labelClient . $_fw . '>:');
|
||||
list($this->rabbitCallbackQueue, ,) = $this->rabbitChannel->queue_declare($label . uniqid(), false, false, false, true);
|
||||
$this->rabbitChannel->basic_consume($this->rabbitCallbackQueue, '', false, true, false, false);
|
||||
$this->rabbitResponse = null;
|
||||
$this->status = true;
|
||||
} catch (AMQPRuntimeException | AMQPTimeoutException | Throwable | TypeError $t) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* call() -- public method
|
||||
*
|
||||
* This method is invoked outside of the class and is the entry point for publishing a message request to the
|
||||
* AdminIn broker. It creates a new AMQP message and publishes it to the queue (defined in the constructor),
|
||||
* and then exits, returning a true message indicating that the messages was successfully published.
|
||||
*
|
||||
* Since the AdminIN broker is a fire-n-forget broker, there are no return messages to block-and-wait on.
|
||||
*
|
||||
* If an exception is raised by this class, then a false value will be returned.
|
||||
*
|
||||
* NOTE: the true/false return values are not, in any way, a reflection of the processing success/failure on the
|
||||
* remote service. The general RoT is that if we can publish the request, then we can only assume that the request
|
||||
* was successfully consumed and processed.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $_data
|
||||
* @return bool
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-15-17 mks original coding
|
||||
* 08-17-17 mks CORE-500: returning a boolean that actually indicates if we successfully published the event
|
||||
* 09-19-19 mks DB-136: refactored exception handling, fixed the AMQPMessage create call
|
||||
* 10-20-20 mks DB-168: better exception handling, removed channel close b/c autodelete is on
|
||||
*
|
||||
*/
|
||||
public function call($_data): bool
|
||||
{
|
||||
$this->rabbitResponse = null;
|
||||
$this->rabbitCorrelationID = uniqid();
|
||||
$success = false;
|
||||
|
||||
try {
|
||||
$rabbitMessage = new AMQPMessage((string)$_data);
|
||||
$this->rabbitChannel->basic_publish($rabbitMessage, '', $this->queueName);
|
||||
$success = true;
|
||||
} catch (AMQPTimeoutException | AMQPRuntimeException | Throwable $e) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $e->getMessage(), $foo, true);
|
||||
}
|
||||
return ($success);
|
||||
}
|
||||
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
// As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
//
|
||||
// destructor is registered shut-down function in constructor -- so any recovery
|
||||
// efforts should go in this method.
|
||||
try {
|
||||
if (!is_null($this->rabbitChannel)) {
|
||||
$this->rabbitChannel->close();
|
||||
$this->rabbitConnection->close();
|
||||
}
|
||||
} catch (AMQPRuntimeException | AMQPTimeoutException | Throwable | TypeError $t) {
|
||||
$hdr = basename(__METHOD__) . AT . __LINE__ . COLON;
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $foo, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
2129
classes/gasCache.class.inc
Normal file
2129
classes/gasCache.class.inc
Normal file
File diff suppressed because it is too large
Load Diff
579
classes/gasConfig.class.inc
Normal file
579
classes/gasConfig.class.inc
Normal file
@@ -0,0 +1,579 @@
|
||||
<?php
|
||||
/**
|
||||
* gasConfig -- static configuration class
|
||||
*
|
||||
* The data framework is intended to read two configuration files of varying types to create a single structure
|
||||
* containing all of the configuration options.
|
||||
*
|
||||
* subsequent requests/instantiations to different configuration files *overwrite* the duplicated-tag sections.
|
||||
*
|
||||
* this approach allows us to load a core configuration, then to modify the structure generated with a second
|
||||
* configuration file.
|
||||
*
|
||||
* class is designed as a singleton so that only one "authoritative" config file can exist.
|
||||
*
|
||||
* To invoke, call the singleton function with the path/filename and the file type:
|
||||
*
|
||||
* $foo = gasConfig::singleton('./config/base.xml', 'xml');
|
||||
*
|
||||
* all configuration file names, and their file types, are defined in the global constants file.
|
||||
*
|
||||
* all key-value-paired data is loaded, stored, and accessed in the classes' $settings member - given a key (tag,
|
||||
* index, etc.), you can access/pull the data using the following:
|
||||
*
|
||||
* $foo = gasConfig::$settings[$key];
|
||||
*
|
||||
* which will either return a value or a sub-array depending on what $key indexes.
|
||||
*
|
||||
* KNOWN LIMITATIONS:
|
||||
* ------------------
|
||||
* Config files have to be supported by the corresponding PHP function that parses that config file type. As of this
|
||||
* writing, only the following file types are supported:
|
||||
*
|
||||
* -- xml
|
||||
* -- ini
|
||||
* -- json
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
* 06-08-18 mks CORE-1035: console logging upgrade
|
||||
* register $setting member function added
|
||||
* 06-15-18 mks CORE-1045: deprecated CONFIG_ID_NODE XML tag
|
||||
* 09-24-19 mks DB-136: deprecated getSyslog() method
|
||||
* 01-08-20 mks DB-150: PHP7.4 class member type-casting
|
||||
*
|
||||
*/
|
||||
class gasConfig
|
||||
{
|
||||
private static ?gasConfig $instance = null; // self-pointer
|
||||
public static ?string $status = null; // used to validate successful instantiation
|
||||
|
||||
// private static $env = [ // defines the valid environments
|
||||
// CONFIG_ID_NODE_NAMASTE,
|
||||
// CONFIG_ID_NODE_ADMIN,
|
||||
// CONFIG_ID_NODE_DEV
|
||||
// ];
|
||||
|
||||
public static ?array $settings = null; // hold all the configs stuffs
|
||||
|
||||
CONST AUTO = 0; // config file format-type associations
|
||||
CONST JSON = 2;
|
||||
const PHP_INI = 4;
|
||||
const XML = 16;
|
||||
|
||||
static private string $res = 'CNFG: '; // logger id tag
|
||||
static private array $CONF_EXT_RELATION = ['json' => 2, 'ini' => 4, 'xml' => 16];
|
||||
|
||||
/**
|
||||
* __construct() -- private method
|
||||
*
|
||||
* constructor function for the class - determines the type of configuration file to read (if none is provided,
|
||||
* then attempt to determine by the file's extension).
|
||||
*
|
||||
* depending on a file extension, invoke the appropriate function to parse the config file in an internal
|
||||
* data structure.
|
||||
*
|
||||
*
|
||||
* @author mshallop@pathway.com
|
||||
* @version 2.1.7
|
||||
*
|
||||
* @param $_cFile
|
||||
* @param string $_fType
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function __construct(string $_cFile, string $_fType = gasConfig::AUTO)
|
||||
{
|
||||
//register_shutdown_function('pgsConfig::__destruct');
|
||||
self::getConfig($_cFile, $_fType);
|
||||
if (gasConfig::$settings[CONFIG_DEBUG]) consoleLog(static::$res, CON_DEBUG, INFO_CONFIG_LOADED);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* registerEnvironment() -- private static method
|
||||
*
|
||||
* This method has no input parameters and returns a boolean to indicate successful processing.
|
||||
*
|
||||
* The method requires that the XML configuration be pre-loaded prior to invocation.
|
||||
*
|
||||
* Method creates an array of services and assigns a boolean value to each service (associative array)
|
||||
* which is then transferred to a member variable.
|
||||
*
|
||||
* Note that "available services" are relative to the local service and not indicative of overall service
|
||||
* ability for a distributed cluster.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-08-18 mks CORE-1035: original coding (transferred from startBrokers.php)
|
||||
* 09-08-20 mks DB-168: updated for XML service locality re-configuration
|
||||
* 11-09-20 mks DB-171: update check for local service registration to also be qualified on ACTIVE setting
|
||||
*
|
||||
*/
|
||||
private static function registerEnvironment(): bool
|
||||
{
|
||||
$environments = [];
|
||||
// using the environment in the XML config -- generate a list of currently-active services.
|
||||
foreach (gasConfig::$settings[CONFIG_REGISTERED_SERVICES][CONFIG_DATABASE_MONGODB_ADMIN_REPLSET_SET] as $service) {
|
||||
if (isset(gasConfig::$settings[CONFIG_BROKER_SERVICES][$service]) and is_array(gasConfig::$settings[CONFIG_BROKER_SERVICES][$service])) {
|
||||
if (isset(gasConfig::$settings[$service][CONFIG_IS_LOCAL])) {
|
||||
if (isset(gasConfig::$settings[$service][CONFIG_ACTIVE])) {
|
||||
$environments[$service] = boolval(gasConfig::$settings[$service][CONFIG_IS_LOCAL]) && boolval(gasConfig::$settings[$service][CONFIG_ACTIVE]);
|
||||
} else {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$msg = $hdr . sprintf(CONFIG_XML_SERVICE_SETTING, CONFIG_BROKER_SERVICES . ARROW . $service . ARROW . CONFIG_IS_LOCAL);
|
||||
consoleLog(static::$res, CON_ERROR, $msg);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$msg = $hdr . sprintf(CONFIG_XML_SERVICE_SETTING, CONFIG_BROKER_SERVICES . ARROW . $service . ARROW . CONFIG_IS_LOCAL);
|
||||
consoleLog(static::$res, CON_ERROR, $msg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] == ENV_PRODUCTION) {
|
||||
// if we're starting in a production environment -- this requires services (appServer, Admin, Segundo and Tercero)
|
||||
// to all be started on separate instances. This block enforces that all services are discrete per instance.
|
||||
if (array_sum($environments) > 1) {
|
||||
$msg = CONFIG_XML_SERVICE_VIOLATION;
|
||||
foreach ($environments as $key => $value) {
|
||||
if ($value == 1) $msg .= $key . ', ';
|
||||
}
|
||||
$msg = rtrim($msg, ', ');
|
||||
consoleLog(static::$res, CON_ERROR, $msg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// save the local services to the gasConfig object
|
||||
static::$settings[CONFIG_REGISTERED_SERVICES] = $environments;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getConfig() -- private static method
|
||||
*
|
||||
* reads the configuration file (passed in by $_cFile) from the DIR_CONFIG directory and merges the files into
|
||||
* (or onto) the existing configuration structure ($settings) on subsequent calls to this method.
|
||||
*
|
||||
* supported file types:
|
||||
* -- json
|
||||
* -- php.ini
|
||||
* -- xml
|
||||
*
|
||||
* if the files cannot be accessed, or if an invalid file type is given, then dump the error to stdout (logfile)
|
||||
* and exit.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $_cFile -- config file path and name
|
||||
* @param string $_fType -- config file type
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private static function getConfig(string $_cFile, string $_fType = gasConfig::AUTO)
|
||||
{
|
||||
$tSettings = null; // temporary holder for file settings
|
||||
|
||||
if ($_fType == self::AUTO) {
|
||||
$_fType = self::$CONF_EXT_RELATION[pathinfo($_cFile, PATHINFO_EXTENSION)];
|
||||
}
|
||||
switch ($_fType) {
|
||||
case self::JSON :
|
||||
$result = file_get_contents($_cFile, true);
|
||||
if (!$result) {
|
||||
consoleLog(static::$res, CON_ERROR, CONFIG_FTL_JSON . $_cFile);
|
||||
return;
|
||||
} else {
|
||||
$tSettings = json_decode($result);
|
||||
}
|
||||
break;
|
||||
|
||||
case self::PHP_INI :
|
||||
$result = parse_ini_file($_cFile, true);
|
||||
if (!$result) {
|
||||
consoleLog(static::$res, CON_ERROR, CONFIG_FTL_INI . $_cFile);
|
||||
return;
|
||||
} else {
|
||||
$tSettings = $result;
|
||||
}
|
||||
break;
|
||||
|
||||
case self::XML :
|
||||
$result = simplexml_load_file($_cFile);
|
||||
if (!$result) {
|
||||
consoleLog(static::$res, CON_ERROR, CONFIG_FTL_XML . $_cFile);
|
||||
return;
|
||||
} else {
|
||||
try {
|
||||
$tSettings = self::objectToArray($result);
|
||||
} catch (TypeError $t) {
|
||||
consoleLog(static::$res, CON_ERROR, ERROR_TYPE_EXCEPTION . COLON . $t->getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!is_null($tSettings)) {
|
||||
if (is_null(self::$settings)) {
|
||||
self::$settings = $tSettings;
|
||||
} else {
|
||||
self::$settings = self::recursiveArrayMerge(self::$settings, $tSettings, true);
|
||||
}
|
||||
try {
|
||||
self::recursiveArrayPurge(self::$settings);
|
||||
} catch (TypeError $t) {
|
||||
consoleLog(static::$res, CON_ERROR, ERROR_TYPE_EXCEPTION . COLON . $t->getMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
// // validate the environment
|
||||
// if (!in_array(self::$settings[CONFIG_ID][CONFIG_ID_NODE], self::$env)) {
|
||||
// consoleLog(static::$res, CON_ERROR, CONFIG_UNK_ENV . self::$settings[CONFIG_ID][CONFIG_ID_NODE]);
|
||||
// exit(1);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* recursiveArrayMerge() -- private static method
|
||||
*
|
||||
* this takes the original configuration array and merges subsequent configuration files on top of it.
|
||||
*
|
||||
* for example, if you have a structure:
|
||||
*
|
||||
* $this[database][mysql] section defined:
|
||||
*
|
||||
* <database>
|
||||
* <mysql>
|
||||
* <db_hostname>localhost</db_hostname>
|
||||
* <db_username>user_name</db_username>
|
||||
* <db_password>user_pass</db_password>
|
||||
* <db_port>3306</db_port>
|
||||
* <db_database>some_database_name</db_database>
|
||||
* </mysql>
|
||||
*
|
||||
* and you want to change the database name for your local environment, then the
|
||||
* subsequent configuration file would bear an identical parent structure, and an
|
||||
* identical element naming structure....changed data within the elements would be
|
||||
* copied over the existing parent structure:
|
||||
*
|
||||
* <database>
|
||||
* <mysql>
|
||||
* <db_database>some_database_name</db_database>
|
||||
* </mysql>
|
||||
*
|
||||
* with the resulting output:
|
||||
* [database] => Array
|
||||
* (
|
||||
* [mysql] => Array
|
||||
* (
|
||||
* [db_hostname] => localhost
|
||||
* [db_username] => user
|
||||
* [db_password] => password
|
||||
* [db_port] => 3306
|
||||
* [db_database] => some_database_name
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $array1
|
||||
* @param $array2
|
||||
* @param bool $overwrite
|
||||
* @return array
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
* 06-20-18 mks CORE-1045: trapped PHP fatal error -- if there's an error in the XML where you have
|
||||
* re-declared a variable (to a different value), the framework IPL will crash.
|
||||
* This fix will prevent the crash from happening and output a console message.
|
||||
*
|
||||
*/
|
||||
public static function recursiveArrayMerge(array $array1, array $array2, bool $overwrite = true)
|
||||
{
|
||||
foreach ($array2 as $key => $val) {
|
||||
if (isset($array1[$key])) {
|
||||
if (is_array($val)) {
|
||||
try {
|
||||
$array1[$key] = self::recursiveArrayMerge($array1[$key], $val);
|
||||
} catch (TypeError $t) {
|
||||
consoleLog(static::$res, CON_SYSTEM, CONFIG_XML_DUP_VAR . $key);
|
||||
consoleLog(static::$res, CON_SYSTEM, $t->getMessage());
|
||||
}
|
||||
} elseif ((is_string($array1[$key]) or is_int($array1[$key])) && $overwrite) {
|
||||
$array1[$key] = $val;
|
||||
}
|
||||
} else {
|
||||
$array1[$key] = $val;
|
||||
}
|
||||
}
|
||||
return $array1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* recursiveArrayPurge() -- local private method
|
||||
*
|
||||
* So, as it turns out, simplexml_load_file() does not ignore comments embedded into the XML... mostly... in truth,
|
||||
* placeholder indices are created within the structure that are also arrays, albeit empty.
|
||||
*
|
||||
* So this function, which is called by the getConfig method, recursively loops through the existing $settings
|
||||
* structure and removes any array with a key of "comment". This, of course, means that one cannot include this
|
||||
* particular value as an index key within the xml file.
|
||||
*
|
||||
* The input parameter to the method is a call-by-reference value which allows us to traverse the settings
|
||||
* structure recursively and retain changes to the overall array.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $ary -- initially, should be the static::$settings array, thereafter, sub-arrays from within
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-13-17 mks original coding
|
||||
* 11-28-17 mks CORE-635: fixed bug in conditional that was causing 0th elements of XML sub-arrays
|
||||
* to be discarded
|
||||
*
|
||||
*/
|
||||
private static function recursiveArrayPurge(array &$ary)
|
||||
{
|
||||
foreach ($ary as $key => &$value) {
|
||||
if ($key === STRING_COMMENT) {
|
||||
unset($ary[$key]);
|
||||
} elseif (is_array($value)) {
|
||||
try {
|
||||
self::recursiveArrayPurge($value);
|
||||
} catch (TypeError $t) {
|
||||
consoleLog(static::$res, CON_ERROR, $t->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* objectToArray() - private static method
|
||||
*
|
||||
* recursive function to flatten objects to a single array.
|
||||
* If the object contains embedded objects, then self-invoke.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $_obj - a collection of either objects or arrays
|
||||
* @return array - the flattened object
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
* 07-21-17 mks CORE-468: if the XML value is numeric (float or int) then return a float or int instead
|
||||
* of a string. Do this by implicitly casting the value by adding 0 to the value.
|
||||
*
|
||||
*/
|
||||
private static function objectToArray($_obj)
|
||||
{
|
||||
$ph = null; // placeholder
|
||||
$ph = (is_object($_obj)) ? get_object_vars($_obj) : $_obj;
|
||||
foreach ($ph as $key => $val) {
|
||||
// todo - evaluate to see if is_array is ever true - if not, use strong typing (SimpleXMLElement)
|
||||
$ph[$key] = ((is_array($val)) or (is_object($val))) ? self::objectToArray($val) : (is_numeric($val) ? $val + 0 : $val);
|
||||
}
|
||||
return ($ph);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __get() -- public method
|
||||
*
|
||||
* This is a magic function for accessing private data within the config class object.
|
||||
* Note that magic functions are required to be public and not static.
|
||||
*
|
||||
* input parameter ($_section) is the string (tag) referencing the (sub)section of the configuration file
|
||||
* to be returned. If $_section does not exist as an array key, or if self::$settings has yet to be set,
|
||||
* then return Boolean(false) -- otherwise return the sub-scripted array as referenced by $_section.
|
||||
*
|
||||
* LIMITATIONS:
|
||||
* ------------
|
||||
* Sub-arrays cannot be deeper than one level.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $_section
|
||||
* @return bool
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __get($_section)
|
||||
{
|
||||
return (is_array(self::$settings) and (array_key_exists($_section, self::$settings)) ? self::$settings[$_section] : false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getPedigree() -- public static function
|
||||
*
|
||||
* This function has no input parameters and returns an associative array.
|
||||
*
|
||||
* The function pulls the current configuration and returns selected parameters to the calling client. These values
|
||||
* are going to be string values, except for the current version which is cast to float, and will indicate if a
|
||||
* feature is enabled, disabled or, if there's a configuration error, set to an error message.
|
||||
*
|
||||
* It's the responsibility of the calling program to parse the return array and to compare/contrast the selected
|
||||
* values.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-09-18 mks CORE-1017: original coding
|
||||
*
|
||||
*/
|
||||
public static function getPedigree(): array
|
||||
{
|
||||
$retData[PEDIGREE_ENV] = isset(gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV]) ? gasConfig::$settings[CONFIG_ID][CONFIG_ID_ENV] : ERROR_STUB_NOTDEF;
|
||||
$retData[PEDIGREE_VER] = isset(gasConfig::$settings[CONFIG_ID][CONFIG_ID_VER]) ? floatval(gasConfig::$settings[CONFIG_ID][CONFIG_ID_VER]) : ERROR_STUB_NOTDEF;
|
||||
$retData[PEDIGREE_DEBUG] = isset(gasConfig::$settings[CONFIG_DEBUG]) ? ((intval(gasConfig::$settings[CONFIG_DEBUG]) == 1) ? STRING_ENABLED : STRING_DISABLED) : ERROR_STUB_NOTDEF;
|
||||
$retData[PEDIGREE_SYSLOG] = STRING_ENABLED;
|
||||
$retData[PEDIGREE_AUDIT] = isset(gasConfig::$settings[CONFIG_AUDIT_ON]) ? ((intval(gasConfig::$settings[CONFIG_AUDIT_ON]) == 1) ? STRING_ENABLED : STRING_DISABLED) : ERROR_STUB_NOTDEF;
|
||||
$retData[PEDIGREE_JOURNAL] = isset(gasConfig::$settings[CONFIG_JOURNAL_ON]) ? ((intval(gasConfig::$settings[CONFIG_JOURNAL_ON]) == 1) ? STRING_ENABLED : STRING_DISABLED) : ERROR_STUB_NOTDEF;
|
||||
$retData[PEDIGREE_SEGUNDO] = isset(gasConfig::$settings[CONFIG_BROKER_SEGUNDO]) ? ((intval(gasConfig::$settings[CONFIG_BROKER_SEGUNDO]) == 1) ? STRING_ENABLED : STRING_DISABLED) : ERROR_STUB_NOTDEF;
|
||||
$retData[PEDIGREE_TERCERO] = isset(gasConfig::$settings[CONFIG_BROKER_TERCERO]) ? ((intval(gasConfig::$settings[CONFIG_BROKER_TERCERO]) == 1) ? STRING_ENABLED : STRING_DISABLED) : ERROR_STUB_NOTDEF;
|
||||
$retData[PEDIGREE_QTAG] = isset(gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG]) ? gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_QUEUE_TAG] : ERROR_STUB_NOTDEF;
|
||||
$retData[PEDIGREE_VHOST] = isset(gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_VHOST]) ? gasConfig::$settings[CONFIG_BROKER_SERVICES][CONFIG_BROKER_VHOST] : ERROR_STUB_NOTDEF;
|
||||
return $retData;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* singleton() -- public static function
|
||||
*
|
||||
* the problem with php is that it does not support true static classes. If you add a debug output to this method
|
||||
* when it's entered, you'll see it proc every time this method is called.
|
||||
*
|
||||
* The input parameters are the name of the configuration file and the configuration file type - which defaults
|
||||
* to the "auto" config type.
|
||||
*
|
||||
* The output is the array structure as defined by the config file itself since it's (more or less) read-in
|
||||
* as the input.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $_iniFile -- path/filename.ext to the config file
|
||||
* @param string $_iniType -- extension type of the config file
|
||||
* @return gasConfig -- returns an array or false
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public static function singleton(string $_iniFile, string $_iniType = gasConfig::AUTO): gasConfig
|
||||
{
|
||||
if (static::$instance === null) {
|
||||
$c = __CLASS__;
|
||||
static::$instance = new $c($_iniFile, $_iniType);
|
||||
}
|
||||
return static::$instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* addConfig() -- public static method
|
||||
*
|
||||
* subsequent calls to read-in additional configuration are handled by this method which invokes the private
|
||||
* method already used to load the 0th-case.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param $_file
|
||||
* @param string $_type
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
* 06-08-18 mks CORE-1035: adding service environments to $settings
|
||||
*
|
||||
*/
|
||||
public static function addConfig(string $_file, string $_type = gasConfig::AUTO)
|
||||
{
|
||||
self::getConfig($_file, $_type);
|
||||
|
||||
// now that both env files are loaded, register the service environments:
|
||||
static::$status = false;
|
||||
try {
|
||||
if (!self::registerEnvironment()) {
|
||||
consoleLog(static::$res, CON_ERROR, ERROR_CONFIG_RESOURCE_404 . STRING_SVC_ENV);
|
||||
} else {
|
||||
static::$status = true;
|
||||
}
|
||||
} catch (TypeError $t) {
|
||||
consoleLog(static::$res, CON_ERROR, ERROR_TYPE_EXCEPTION . COLON . $t->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- public static method
|
||||
*
|
||||
* disallow cloning by return an explicit null on the request
|
||||
*
|
||||
* @author mshallop@pathway.com
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
return(null); // disallow cloning of this class
|
||||
}
|
||||
|
||||
}
|
||||
1559
classes/gasResourceManager.class.inc
Normal file
1559
classes/gasResourceManager.class.inc
Normal file
File diff suppressed because it is too large
Load Diff
653
classes/gasStatic.class.inc
Normal file
653
classes/gasStatic.class.inc
Normal file
@@ -0,0 +1,653 @@
|
||||
<?php
|
||||
/**
|
||||
* This is the gasStatic class which is a collection of one-off functions that can be called from a broker or any
|
||||
* instantiation class -- code herein is class-agnostic and storing one-off's here reduces the overhead of a full
|
||||
* class instantiation to accomplish the same functionality.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-09-17 mks original coding
|
||||
* 08-28-17 mks CORE-494: removed buildMappedDataArray() -- method lives in the gasCache class
|
||||
* 03-02-18 mks CORE-680: deprecated trace logging
|
||||
* 07-30-18 mks CORE-774: PHP7.2 Exception handling
|
||||
*
|
||||
*/
|
||||
|
||||
class gasStatic
|
||||
{
|
||||
private static ?gasStatic $instance = null; // used to determine if already instantiated
|
||||
private static string $res = 'STTK: '; // logging resource id
|
||||
public static bool $debug; // debug state for diagnostic output
|
||||
public static bool $available = false; // instantiation-check
|
||||
private static ?array $errors; // local error stack
|
||||
private static string $class; // name of the current class
|
||||
private static ?gacErrorLogger $logger = null;
|
||||
|
||||
/**
|
||||
* __construct() -- private function
|
||||
*
|
||||
* this is the constructor function for this singleton class. the constructor sets the class's member variables
|
||||
* and calls any cache pre-loading that's required.
|
||||
*
|
||||
* Note that the public entry point is via the getInstance() method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-09-17 mks original coding
|
||||
* 07-30-18 mks CORE-774: PHP7.2 Exception handling
|
||||
*
|
||||
*/
|
||||
private function __construct()
|
||||
{
|
||||
global $eos;
|
||||
|
||||
static::$errors = null;
|
||||
try {
|
||||
static::$logger = new gacErrorLogger();
|
||||
} catch (TypeError $t) {
|
||||
echo getDateTime() . CON_ERROR . static::$res . $t->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];
|
||||
}
|
||||
}
|
||||
217
classes/templates/deprecated/xxxLogs.class.inc
Normal file
217
classes/templates/deprecated/xxxLogs.class.inc
Normal file
@@ -0,0 +1,217 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class gatLog
|
||||
*
|
||||
* This is the logging class definition that records framework-generated event messages.
|
||||
*
|
||||
* Design Notes:
|
||||
* -------------
|
||||
* because this is a log, who's events are processed by a FnF queue, we're not going to cache, or use auditing.
|
||||
* History is limited to the created event and deletes are HARD.
|
||||
* Only one status is supported: ACTIVE and there are no updates allowed making record-locking unnecessary.
|
||||
* To reduce overhead, we're not enabling cache timers because recursion.
|
||||
* The collection does not need GUID tokens but we are storing the passed Broker Event ID
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 2.1.3
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*
|
||||
*/
|
||||
class xxxLogs
|
||||
{
|
||||
public $service = CONFIG_DATABASE_DDB_APPSERVER; // defines the nosql server service configuration
|
||||
public $schema = TEMPLATE_DB_DDB; // defines the storage schema for the class
|
||||
public $collection = COLLECTION_MONGO_LOGS; // sets the collection (table) name
|
||||
public $seqKey = COLLECTION_NOSQL_LOGS_SQK; // sets the sequence key identifier
|
||||
public $extension = COLLECTION_MONGO_LOGS_EXT; // sets the extension for the collection
|
||||
public $setCache = false; // set to true to cache class data
|
||||
public $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public $setJournaling = false; // set to true to allow journaling
|
||||
public $setUpdates = false; // set to true to allow record updates
|
||||
public $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public $setLocking = false; // set to true to enable record locking for collection
|
||||
public $setTimers = false; // set to true to enable collection query timers
|
||||
public $setPKeyType = DB_TOKEN; // sets the primary key type: either ID or TOKEN
|
||||
|
||||
/*
|
||||
* tokens are guids -- if you're using a guid as the pkey for the class, then this value should be false.
|
||||
* if you're using an integer pkey, and you want a token, you have to explicitly declare
|
||||
* the token fields in $fields and set this value to true.
|
||||
* if you're using an integer pkey and you don't want a token, set this value to false.
|
||||
*/
|
||||
public $setTokens = false; // set to true: adds the idToken field functionality
|
||||
public $selfDestruct = true; // set to false if the class contains methods
|
||||
public $cacheTimer = 0; // number of seconds a tuple will remain in-cache
|
||||
public $setEnv = ENV_ALL; // defines the env where this class can be accessed
|
||||
public $setMeta = false; // defines if we'll use the meta package for history
|
||||
|
||||
public $fields = [
|
||||
DB_PKEY => DDB_TYPE_STRING, // GUID because setPKeyType == DB_TOKEN
|
||||
LOG_FILE => DDB_TYPE_STRING,
|
||||
LOG_METHOD => DDB_TYPE_STRING,
|
||||
LOG_LINE => DDB_TYPE_NUMBER,
|
||||
LOG_CLASS => DDB_TYPE_STRING,
|
||||
LOG_LEVEL => DDB_TYPE_STRING,
|
||||
LOG_MESSAGE => DDB_TYPE_STRING,
|
||||
LOG_STACK_TRACE => DDB_TYPE_LIST,
|
||||
DB_STATUS => DDB_TYPE_STRING,
|
||||
DB_HISTORY => DDB_TYPE_LIST,
|
||||
LOG_IS_EVENT => DDB_TYPE_BOOLEAN,
|
||||
LOG_EVENT_GUID => DDB_TYPE_STRING,
|
||||
LOG_CREATED => DDB_TYPE_NUMBER
|
||||
];
|
||||
|
||||
public $fieldTypes = [
|
||||
DB_PKEY => DATA_TYPE_STRING, // guid
|
||||
LOG_FILE => DATA_TYPE_STRING,
|
||||
LOG_METHOD => DATA_TYPE_STRING,
|
||||
LOG_LINE => DATA_TYPE_INTEGER,
|
||||
LOG_CLASS => DATA_TYPE_STRING,
|
||||
LOG_LEVEL => DATA_TYPE_STRING,
|
||||
LOG_MESSAGE => DATA_TYPE_STRING,
|
||||
LOG_STACK_TRACE => DATA_TYPE_ARRAY,
|
||||
DB_STATUS => DATA_TYPE_STRING,
|
||||
DB_TIMER => DATA_TYPE_DOUBLE,
|
||||
DB_HISTORY => DATA_TYPE_ARRAY,
|
||||
LOG_IS_EVENT => DATA_TYPE_BOOL,
|
||||
LOG_EVENT_GUID => DATA_TYPE_STRING,
|
||||
LOG_CREATED => DATA_TYPE_INTEGER
|
||||
];
|
||||
|
||||
// in the ddb world, this is the primary composite key for this table
|
||||
public $indexes = [ DB_PKEY => DDB_INDEX_HASH, LOG_CREATED => DDB_INDEX_RANGE ];
|
||||
|
||||
/*
|
||||
* declaring global and local secondary indexes:
|
||||
*
|
||||
* Limit: 5 of each
|
||||
*
|
||||
* General Format:
|
||||
* ---------------
|
||||
* Each tuple, up to the limit, is a record that contains the following array structure:
|
||||
*
|
||||
* [[
|
||||
* 'name' => INDEX_NAME, // REQUIRED
|
||||
* 'indexes' => [ KEY_NAME => HASH {, KEY_NAME => RANGE } ], // REQUIRED
|
||||
* 'projectionType' => { KEYS_ONLY | INCLUDE | ALL }, // REQUIRED
|
||||
* 'nka' => { [ list of one or more non-key attributes !>20 ] }, // REQUIRED if projection = INCLUDE
|
||||
* 'throughput' => [ 'rcu' => <integer>, 'wcu' => <integer> ] // REQUIRED for GLOBAL only
|
||||
* ],....];
|
||||
*
|
||||
* secondary index keys must use the key literals as shown above. ('name', 'indexes', 'projectionType', etc.)
|
||||
*
|
||||
*/
|
||||
public $globalIndexes = array(
|
||||
[
|
||||
// this creates a partition key based on the log level (fatal, warn, debug, etc.) with a sort key
|
||||
// based on the method (the class method that created the log event).
|
||||
// query example: give me all fatal errors
|
||||
// give me all warnings generate by the method: _fetchData()
|
||||
// Since the base keys (id, date) are projected onto this index, I am (awaiting testing) assuming
|
||||
// that you could also range your query based on the creation date.
|
||||
STRING_NAME => 'index_log_level',
|
||||
STRING_INDEXES => [ LOG_LEVEL => DDB_INDEX_HASH, LOG_METHOD => DDB_INDEX_RANGE ],
|
||||
DDB_STRING_PT => DDB_PT_ALL,
|
||||
STRING_THROUGHPUT => [ CONFIG_DATABASE_READ_CAPACITY_UNITS => 100, CONFIG_DATABASE_WRITE_CAPACITY_UNITS => 100 ]
|
||||
],
|
||||
[
|
||||
// lets add a second global index: key will be the created date, and the sort will be the error level
|
||||
// this will allow us to answer queries like:
|
||||
// give me all errors in the last hour
|
||||
// give me all fatal errors for January
|
||||
STRING_NAME => 'index_log_created',
|
||||
STRING_INDEXES => [ LOG_CREATED => DDB_INDEX_HASH, LOG_LEVEL => DDB_INDEX_RANGE ],
|
||||
DDB_STRING_PT => DDB_PT_INCLUDE,
|
||||
DDB_STRING_NON_KEY_ATTRIBUTE => [ LOG_FILE, LOG_CLASS, LOG_METHOD, LOG_LINE ],
|
||||
STRING_THROUGHPUT => [ CONFIG_DATABASE_READ_CAPACITY_UNITS => 100, CONFIG_DATABASE_WRITE_CAPACITY_UNITS => 100 ]
|
||||
]
|
||||
);
|
||||
|
||||
public $localIndexes = array(
|
||||
[
|
||||
// create secondary index using the log-level as the range value making the assumption that the
|
||||
// base index hash will be used as the local secondary hash
|
||||
STRING_NAME => 'index_sec_level',
|
||||
STRING_INDEXES => [ DB_PKEY => DDB_INDEX_HASH, LOG_LEVEL => DDB_INDEX_RANGE ],
|
||||
DDB_STRING_PT => DDB_PT_ALL
|
||||
]
|
||||
);
|
||||
|
||||
public $exposedFields = null; // list of fields exposed to clients
|
||||
public $cacheMap = null; // k->v paired array mapping fields -> cachedField Names
|
||||
public $binFields = null; // binary fields that have to be encoded
|
||||
|
||||
// these fields aren't used in DDB, but are used in mongo, so are here only for code-compatibility
|
||||
public $uniqueIndexes = null;
|
||||
public $sparseIndexes = null;
|
||||
public $subCollections = null;
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
185
classes/templates/deprecated/xxxMetrics.class.inc
Normal file
185
classes/templates/deprecated/xxxMetrics.class.inc
Normal file
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class pgtMetrics
|
||||
*
|
||||
* This is the metrics class definition that records timer events, usually database queries.
|
||||
*
|
||||
* Design Notes:
|
||||
* -------------
|
||||
* Metrics is identical to Logs, who's events are processed by a FnF queue, we're not going to cache, or use auditing.
|
||||
* History is limited to the created event and deletes are HARD.
|
||||
* Only one status is supported: ACTIVE and there are no updates allowed making record-locking unnecessary.
|
||||
* To reduce overhead, we're not enabling cache timers because recursive.
|
||||
* The collection does not need GUID tokens but we are storing the passed session ID in the meta payload for the
|
||||
* create event - which is the only history event required or logged.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks code complete
|
||||
*
|
||||
*/
|
||||
class xxxMetrics
|
||||
{
|
||||
public $service = CONFIG_DATABASE_DDB_APPSERVER; // defines the nosql server service configuration
|
||||
public $schema = TEMPLATE_DB_DDB; // defines the storage schema for the class
|
||||
public $collection = COLLECTION_MONGO_METRICS; // sets the collection (table) name
|
||||
public $seqKey = COLLECTION_NOSQL_METRICS_SQK; // sets the sequence key identifier
|
||||
public $extension = COLLECTION_MONGO_METRICS_EXT; // sets the extension for the collection
|
||||
public $setCache = false; // set to true to cache class data
|
||||
public $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public $setJournaling = false; // set to true to enable journaling
|
||||
public $setUpdates = false; // set to true to allow record updates
|
||||
public $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public $setLocking = false; // set to true to enable record locking for collection
|
||||
public $setTimers = false; // set to true to enable collection query timers
|
||||
public $setPKeyType = DB_TOKEN; // sets the primary key type: either ID or TOKEN
|
||||
/*
|
||||
* tokens are guids -- if you're using a guid as the pkey for the class, then this value should be false.
|
||||
* if you're using an integer pkey, and you want a token, you have to explicitly declare
|
||||
* the token fields in $fields and set this value to true.
|
||||
* if you're using an integer pkey and you don't want a token, set this value to false.
|
||||
*/
|
||||
public $setTokens = false; // set to true: adds the idToken field functionality
|
||||
public $selfDestruct = true; // set to false if the class contains methods
|
||||
public $cacheTimer = 0; // number of seconds a tuple will remain in-cache
|
||||
public $setEnv = ENV_ALL; // defines the env where this class can be accessed
|
||||
public $setMeta = false; // defines if we'll use the meta package for history
|
||||
|
||||
public $fields = [
|
||||
DB_PKEY => DDB_TYPE_STRING, // GUID because setPKeyType == DB_TOKEN
|
||||
LOG_FILE => DDB_TYPE_STRING,
|
||||
LOG_METHOD => DDB_TYPE_STRING,
|
||||
LOG_LINE => DDB_TYPE_NUMBER,
|
||||
LOG_CLASS => DDB_TYPE_STRING,
|
||||
LOG_LEVEL => DDB_TYPE_STRING,
|
||||
LOG_MESSAGE => DDB_TYPE_STRING,
|
||||
LOG_STACK_TRACE => DDB_TYPE_LIST,
|
||||
DB_STATUS => DDB_TYPE_STRING,
|
||||
DB_TIMER => DDB_TYPE_NUMBER,
|
||||
DB_HISTORY => DDB_TYPE_LIST,
|
||||
LOG_IS_EVENT => DDB_TYPE_BOOLEAN,
|
||||
LOG_EVENT_GUID => DDB_TYPE_STRING,
|
||||
LOG_CREATED => DDB_TYPE_NUMBER
|
||||
];
|
||||
|
||||
public $fieldTypes = [
|
||||
DB_PKEY => DATA_TYPE_STRING, // guid
|
||||
LOG_FILE => DATA_TYPE_STRING,
|
||||
LOG_METHOD => DATA_TYPE_STRING,
|
||||
LOG_LINE => DATA_TYPE_INTEGER,
|
||||
LOG_CLASS => DATA_TYPE_STRING,
|
||||
LOG_LEVEL => DATA_TYPE_STRING,
|
||||
LOG_MESSAGE => DATA_TYPE_STRING,
|
||||
LOG_STACK_TRACE => DATA_TYPE_ARRAY,
|
||||
DB_STATUS => DATA_TYPE_STRING,
|
||||
DB_TIMER => DATA_TYPE_DOUBLE,
|
||||
DB_HISTORY => DATA_TYPE_ARRAY,
|
||||
LOG_IS_EVENT => DATA_TYPE_BOOL,
|
||||
LOG_EVENT_GUID => DATA_TYPE_STRING,
|
||||
LOG_CREATED => DATA_TYPE_INTEGER
|
||||
];
|
||||
|
||||
// in the ddb world, this is the primary composite key for this table
|
||||
public $indexes = [ DB_PKEY => DDB_INDEX_HASH, LOG_CREATED => DDB_INDEX_RANGE ];
|
||||
|
||||
/*
|
||||
* declaring global and local secondary indexes:
|
||||
*
|
||||
* Limit: 5 of each
|
||||
*
|
||||
* General Format:
|
||||
* ---------------
|
||||
* Each tuple, up to the limit, is a record that contains the following array structure:
|
||||
*
|
||||
* [[
|
||||
* 'name' => INDEX_NAME, // REQUIRED
|
||||
* 'indexes' => [ KEY_NAME => HASH {, KEY_NAME => RANGE } ], // REQUIRED
|
||||
* 'projectionType' => { KEYS_ONLY | INCLUDE | ALL }, // REQUIRED
|
||||
* 'nka' => { [ list of one or more non-key attributes !>20 ] }, // REQUIRED if projection = INCLUDE
|
||||
* 'throughput' => [ 'rcu' => <integer>, 'wcu' => <integer> ] // REQUIRED for GLOBAL only
|
||||
* ],....];
|
||||
*
|
||||
* secondary index keys must use the key literals as shown above. ('name', 'indexes', 'projectionType', etc.)
|
||||
*
|
||||
*/
|
||||
public $globalIndexes = null;
|
||||
public $localIndexes = null;
|
||||
|
||||
public $exposedFields = null; // list of fields exposed to clients
|
||||
public $cacheMap = null; // k->v paired array mapping fields -> cachedField Names
|
||||
public $binFields = null; // binary fields that have to be encoded
|
||||
|
||||
// these fields aren't used in DDB, but are used in mongo, so are here only for code-compatibility
|
||||
public $uniqueIndexes = null;
|
||||
public $sparseIndexes = null;
|
||||
public $subCollections = null;
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-07-17 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
87
classes/templates/deprecated/xxxTestMySQL.class.inc
Normal file
87
classes/templates/deprecated/xxxTestMySQL.class.inc
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class: gatTestMySQL
|
||||
*
|
||||
* This is the definition for a mysql/mariadb-based test class. Intended usage is for unit-testing for basic CRUD
|
||||
* operations.
|
||||
*
|
||||
* This template should also serve as a guide, or documentation, for creating mysql/mariadb template classes.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-30-17 mks original coding
|
||||
*
|
||||
*/
|
||||
class gatTestMySQL
|
||||
{
|
||||
public $version = 1;
|
||||
public $schema = TEMPLATE_DB_PDO; // defines the storage schema for the class
|
||||
public $collection = COLLECTION_MYSQL_TEST; // sets the collection (table) name
|
||||
public $seqKey = COLLECTION_MYSQL_TEST_SQK; // sets the sequence key identifier
|
||||
public $extension = COLLECTION_MYSQL_TEST_EXT; // sets the extension for the collection
|
||||
public $setCache = true; // set to true to cache class data
|
||||
public $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public $setJournaling = false; // set to true to allow journaling
|
||||
public $setUpdates = true; // set to true to allow record updates
|
||||
public $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public $setLocking = false; // set to true to enable record locking for collection
|
||||
public $setTimers = true; // set to true to enable collection query timers
|
||||
public $setPKey = DB_PKEY; // sets the primary key for the collection
|
||||
public $selfDestruct = true; // set to false if this class contains methods
|
||||
|
||||
/*
|
||||
* tokens are guids -- if you're using a guid as the pkey for the class, then this value should be false.
|
||||
* if you're using an integer pkey, and you want a token, you have to explicitly declare
|
||||
* the token fields in $fields and set this value to true.
|
||||
* if you're using an integer pkey and you don't want a token, set this value to false.
|
||||
*/
|
||||
public $setTokens = false; // set to true: adds the idToken field functionality
|
||||
public $cacheTimer = 0; // number of seconds a tuple will remain in-cache
|
||||
public $setEnv = ENV_ALL; // defines the env where this class can be accessed
|
||||
public $setMeta = false; // defines if we'll use the meta package for history
|
||||
|
||||
public $fields = [
|
||||
DB_PKEY => DATA_TYPE_INTEGER, // pkey (integer) used internally and is REQUIRED
|
||||
TEST_FIELD_TEST_STRING => DATA_TYPE_STRING,
|
||||
TEST_FIELD_TEST_DOUBLE => DATA_TYPE_DOUBLE,
|
||||
TEST_FIELD_TEST_INT => DATA_TYPE_INTEGER,
|
||||
TEST_FIELD_TEST_BOOL => DATA_TYPE_BOOL,
|
||||
TEST_FIELD_TEST_OBJECT => DATA_TYPE_OBJECT,
|
||||
DB_TOKEN => DATA_TYPE_STRING // unique key (string) exposed externally and is REQUIRED
|
||||
];
|
||||
|
||||
// cache-map constants are in ./common/cacheMaps.php
|
||||
public $cacheMap = [
|
||||
DB_TOKEN => CM_TST_TOKEN,
|
||||
TEST_FIELD_TEST_STRING => CM_TST_FIELD_TEST_STRING,
|
||||
TEST_FIELD_TEST_DOUBLE => CM_TST_FIELD_TEST_DOUBLE,
|
||||
TEST_FIELD_TEST_INT => CM_TST_FIELD_TEST_INT,
|
||||
TEST_FIELD_TEST_BOOL => CM_TST_FIELD_TEST_BOOL,
|
||||
TEST_FIELD_TEST_OBJECT => CM_TST_FIELD_TEST_OBJ
|
||||
];
|
||||
|
||||
// for mysql, all indexed fields are listed in this container regardless of index type. If an field appears but
|
||||
// is not a unique or compound index, then it is just a regular index.
|
||||
public $indexes = [ DB_PKEY, TEST_FIELD_TEST_INT, DB_TOKEN ];
|
||||
|
||||
// unique indexes listed as an indexed array
|
||||
public $uniqueIndexes = [ DB_TOKEN ];
|
||||
|
||||
// compound indexes are listed as sub-arrays:
|
||||
// [ [ col-1, ..., col-n ], ..., [] ]
|
||||
public $compoundIndexes = null;
|
||||
|
||||
// exposed fields are mutually exclusive with cacheMaps; one or the other but not both
|
||||
public $exposedFields = null;
|
||||
|
||||
// binary fields require special handling (encoding) and have to be listed here
|
||||
public $binaryFields = null;
|
||||
}
|
||||
529
classes/templates/gatAudit.class.inc
Normal file
529
classes/templates/gatAudit.class.inc
Normal file
@@ -0,0 +1,529 @@
|
||||
<?php
|
||||
/**
|
||||
* gatAudit Class Template -- mongo template class
|
||||
*
|
||||
* This is the template class for the Audit table - the auditing sub-system for Namaste.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-16-18 mks DB-57: original coding
|
||||
* 11-13-18 mks DB-63: added template field to collection fields/schema
|
||||
* 01-13-20 mks DB-150: PHP7.4 member type casting
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
|
||||
class gatAudit
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_ADMIN; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_AUDIT; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_AUDIT; // sets the collection (table) name
|
||||
public ?string $whTemplate = TEMPLATE_CLASS_AUDIT; // name of the warehouse template (not collection)
|
||||
public string $extension = COLLECTION_MONGO_AUDIT_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = false; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
// fields specific to the collection
|
||||
MONGO_ID => DATA_TYPE_OBJECT, // sorting by the id is just like sorting by createdDate
|
||||
AUDIT_SYS_EV_GUID => DATA_TYPE_STRING, // GUID passed from the System Event Manager
|
||||
AUDIT_SESSION_GUID => DATA_TYPE_STRING, // Session GUID (pulled from meta payload)
|
||||
AUDIT_SESSION_IP => DATA_TYPE_STRING, // Session IP (pulled from meta payload)
|
||||
AUDIT_USER_GUID => DATA_TYPE_STRING, // User GUID (pulled from meta payload)
|
||||
AUDIT_JOURNAL_GUID => DATA_TYPE_STRING, // (optional) Journal Event GUID
|
||||
AUDIT_SERVICE => DATA_TYPE_STRING, // service of the collection/record under audit
|
||||
AUDIT_SCHEMA => DATA_TYPE_STRING, // schema type for the accessed collection/table
|
||||
AUDIT_TEMPLATE => DATA_TYPE_STRING, // the template name used to instantiate the data class
|
||||
AUDIT_DB => DATA_TYPE_STRING, // name of the DB being accessed
|
||||
AUDIT_COLLECTION => DATA_TYPE_STRING, // name of the collection/table being accessed
|
||||
AUDIT_COLLECTION_EXT => DATA_TYPE_STRING, // Namaste extension of the targeted table (todo: not sure yet why I need/want this)
|
||||
AUDIT_RECORD_TOKEN => DATA_TYPE_STRING, // record GUID
|
||||
AUDIT_SNAPSHOT => DATA_TYPE_STRING, // JSON-encoded copy of the record prior to access
|
||||
AUDIT_QUERY => DATA_TYPE_STRING, // copy of the query used to access the record
|
||||
AUDIT_ACCESS_CLIENT => DATA_TYPE_STRING, // name of the application/client used to access the record
|
||||
AUDIT_ACCESS_USER => DATA_TYPE_STRING, // name of the user accessing the record (if available)
|
||||
AUDIT_USER_ROLE => DATA_TYPE_STRING, // role of the user accessing the record (if available)
|
||||
AUDIT_OPERATION => DATA_TYPE_STRING, // name of the operation access the record (CRUD)
|
||||
AUDIT_ACCESS_ALLOWED => DATA_TYPE_BOOL, // if the access was granted or blocked
|
||||
// generic mongo constants
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (string) exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER // epoch time
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
// todo -- code a condition where ALL fields are protected using the * symbol (DB-58)
|
||||
public ?array $protectedFields = [
|
||||
MONGO_ID, AUDIT_SYS_EV_GUID, AUDIT_SESSION_GUID, AUDIT_USER_GUID, AUDIT_JOURNAL_GUID, AUDIT_SERVICE,
|
||||
AUDIT_SCHEMA, AUDIT_DB, AUDIT_COLLECTION, AUDIT_COLLECTION_EXT, AUDIT_SNAPSHOT, AUDIT_QUERY,
|
||||
AUDIT_ACCESS_CLIENT, AUDIT_ACCESS_USER, AUDIT_USER_ROLE, AUDIT_OPERATION, AUDIT_ACCESS_ALLOWED,
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_STATUS, DB_ACCESSED, AUDIT_RECORD_TOKEN, AUDIT_TEMPLATE
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_CREATED, DB_TOKEN, DB_ACCESSED, DB_EVENT_GUID, AUDIT_SYS_EV_GUID, AUDIT_USER_GUID,
|
||||
AUDIT_JOURNAL_GUID, AUDIT_ACCESS_ALLOWED, AUDIT_SESSION_GUID, AUDIT_SESSION_IP, AUDIT_RECORD_TOKEN
|
||||
];
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_CREATED => -1, // assuming we want LIFO
|
||||
DB_ACCESSED => -1, // assuming we want LIFO
|
||||
DB_EVENT_GUID => 1, // event guid should always be indexed
|
||||
AUDIT_ACCESS_ALLOWED => 1,
|
||||
AUDIT_SESSION_IP => 1,
|
||||
AUDIT_RECORD_TOKEN => 1
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1, // MONGO_TOKEN should always appear
|
||||
AUDIT_SESSION_GUID => 1,
|
||||
AUDIT_JOURNAL_GUID => 1,
|
||||
AUDIT_USER_GUID => 1,
|
||||
AUDIT_SYS_EV_GUID => 1
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = null;
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
* SubC fields do not need to be indexed.
|
||||
*
|
||||
*/
|
||||
public ?array $subC = null;
|
||||
|
||||
//=================================================================================================================
|
||||
// MIGRATION DECLARATIONS
|
||||
// ----------------------
|
||||
// Data in this section is used to handle migrations -- when we're pulling from legacy tables into the Namaste
|
||||
// framework. See online doc for more info.
|
||||
//=================================================================================================================
|
||||
|
||||
/**
|
||||
* The migration map is an associative array that maps the Namaste fields (keys) to the corresponding
|
||||
* (remote) legacy fields in the source table to be migrated to Namaste.
|
||||
*
|
||||
* For example, if we were migrating a mysql table in the legacy production database to Namaste::mongo, then
|
||||
* the keys of the migration map would be the Namaste::mongo->fieldNames and the values would be the mysql
|
||||
* column names in the legacy table.
|
||||
*
|
||||
* If there is a value which cannot be mapped to a key, then set it to null.
|
||||
*
|
||||
* Fields that will be dropped in the migration are not listed as values or as keys.
|
||||
*
|
||||
* This map will only exist in the template object and will never be imported into the class widget.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationMap = null;
|
||||
|
||||
/*
|
||||
* the migrationSortKey defines the SOURCE field by which the fetch query will be sorted. ALL sort fields are
|
||||
* in ASC order so all we need to list here is the name of the field -- which MUST BE IN THE SOURCE TABLE.
|
||||
*
|
||||
* Populating this field may require preliminary examination of the data - what we want is a field that has
|
||||
* zero NULL values.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationSortKey = null;
|
||||
|
||||
/*
|
||||
* The migrationStatusKey defines the status field/column in the source table -- if the user requires that
|
||||
* soft-deleted records not be migrated, then this field must be set. Otherwise, set the value to null.
|
||||
*
|
||||
* The format is in the form of a key-value paired array. The key specifies the name of the column and the value
|
||||
* specifies the "deleted" value that, if found, will cause that row from the SOURCE data to be omitted from the
|
||||
* DESTINATION table.
|
||||
*
|
||||
* e.g.: $migrationStatusKV = [ 'some_field' => 'deleted' ]
|
||||
*
|
||||
* Note that both the key and the value are case-sensitive!
|
||||
*
|
||||
* This is an optional field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationStatusKV = null;
|
||||
|
||||
// The $migrationSourceSchema defines the remote schema for the source table
|
||||
public ?string $migrationSourceSchema = null; // or STRING_MONGO
|
||||
|
||||
// The source table in the remote repos (default defined in the XML) must be declared here
|
||||
public ?string $migrationSourceTable = null;
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => true, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'Q', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => true, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
WH_INDEXES => [DB_CREATED, DB_WH_CREATED],
|
||||
WH_TEMPLATE => '',
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [ OPERAND_NULL => [ OPERATOR_LT => [ null ] ] ],
|
||||
DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-16-18 mks DB-57: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-16-18 mks DB-57: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-16-18 mks DB-57: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
808
classes/templates/gatConsolidatedSanctionsList.class.inc
Normal file
808
classes/templates/gatConsolidatedSanctionsList.class.inc
Normal file
@@ -0,0 +1,808 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class gatConsolidatedSanctionsList -- mongo class
|
||||
*
|
||||
* This class is used to store the US DHS Consolidated Sanctions list found at:
|
||||
* https://home.treasury.gov/policy-issues/financial-sanctions/consolidated-sanctions-list-data-files
|
||||
* This collection is populated from the file: consolidated.xml, an XML version of the Consolidated Sanctions list
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-03-20 mks DB-179: original coding
|
||||
*
|
||||
*/
|
||||
class gatConsolidatedSanctionsList
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version; not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_SEGUNDO; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_CSL; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_CSL; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_CSL_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = false; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = false; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_DESTRUCTIVE; // set to AUDIT_value constant (nondestructive = reads(yes))
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = true; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search statusz
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
public array $fields = [
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER, // epoch time
|
||||
COLLECTION_MONGO_CSL_ADDRESS => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_ADDRESS1 => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_ADDRESS2 => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_ADDRESS3 => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_ADDR_LIST => DATA_TYPE_ARRAY,
|
||||
COLLECTION_MONGO_CSL_AKA => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_AKA_LIST => DATA_TYPE_ARRAY,
|
||||
COLLECTION_MONGO_CSL_CATEGORY => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_CITIZENSHIP => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_CITIZENSHIP_LIST => DATA_TYPE_ARRAY,
|
||||
COLLECTION_MONGO_CSL_CITY => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_COUNTRY => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_DOB => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_DOB_LIST => DATA_TYPE_ARRAY,
|
||||
COLLECTION_MONGO_CSL_FN => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_LN => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_ID => DATA_TYPE_INTEGER,
|
||||
COLLECTION_MONGO_CSL_ID_COUNTRY => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_ID_LIST => DATA_TYPE_ARRAY,
|
||||
COLLECTION_MONGO_CSL_ID_NUMBER => DATA_TYPE_STRING, // because leading zeros
|
||||
COLLECTION_MONGO_CSL_ID_TYPE => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_MAIN_ENTRY => DATA_TYPE_BOOL,
|
||||
COLLECTION_MONGO_CSL_POB => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_POB_LIST => DATA_TYPE_ARRAY,
|
||||
COLLECTION_MONGO_CSL_POSTAL_CODE => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_PRG => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_PRG_LIST => DATA_TYPE_ARRAY,
|
||||
COLLECTION_MONGO_CSL_REMARKS => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_SOP => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_TYPE => DATA_TYPE_STRING,
|
||||
COLLECTION_MONGO_CSL_UID => DATA_TYPE_INTEGER,
|
||||
COLLECTION_MONGO_CSL_SDN_TYPE => DATA_TYPE_STRING
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, DB_STATUS
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_CREATED, DB_EVENT_GUID, DB_ACCESSED, MONGO_ID, DB_STATUS
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_TOKEN, DB_CREATED, DB_STATUS, DB_EVENT_GUID, COLLECTION_MONGO_CSL_AKA_LIST,
|
||||
COLLECTION_MONGO_CSL_DOB_LIST, COLLECTION_MONGO_CSL_ADDR_LIST, COLLECTION_MONGO_CSL_SDN_TYPE
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = ['EntityNameIndex'];
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_TOKEN => 1,
|
||||
DB_CREATED => -1,
|
||||
DB_STATUS => 1,
|
||||
COLLECTION_MONGO_CSL_SDN_TYPE => 1
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = [
|
||||
'EntityNameIndex' => [COLLECTION_MONGO_CSL_SDN_TYPE, COLLECTION_MONGO_CSL_LN, COLLECTION_MONGO_CSL_LN]
|
||||
];
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Sparse indexes only add the row to the index if the column referenced satisfies the conditions specified
|
||||
// in the query condition (expr2).
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1 // MONGO_TOKEN should always appear
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
// cache maps are required for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
DB_TOKEN => CM_TOKEN,
|
||||
DB_CREATED => CM_DATE_CREATED,
|
||||
DB_ACCESSED => CM_DATE_ACCESSED,
|
||||
DB_STATUS => CM_STATUS,
|
||||
DB_EVENT_GUID => CM_EVENT_GUID,
|
||||
CM_CSL_ADDR => COLLECTION_MONGO_CSL_ADDRESS,
|
||||
CM_CSL_ADDR1 => COLLECTION_MONGO_CSL_ADDRESS1,
|
||||
CM_CSL_ADDR2 => COLLECTION_MONGO_CSL_ADDRESS2,
|
||||
CM_CSL_ADDR3 => COLLECTION_MONGO_CSL_ADDRESS3,
|
||||
CM_CSL_ADDR_LIST => COLLECTION_MONGO_CSL_ADDR_LIST,
|
||||
CM_CSL_AKA => COLLECTION_MONGO_CSL_AKA,
|
||||
CM_CSL_AKA_LIST => COLLECTION_MONGO_CSL_AKA_LIST,
|
||||
CM_CSL_CAT => COLLECTION_MONGO_CSL_CATEGORY,
|
||||
CM_CSL_CITIZENSHIP => COLLECTION_MONGO_CSL_CITIZENSHIP,
|
||||
CM_CSL_CITIZENSHIP_LIST => COLLECTION_MONGO_CSL_CITIZENSHIP_LIST,
|
||||
CM_CSL_CITY => COLLECTION_MONGO_CSL_CITY,
|
||||
CM_CSL_COUNTRY => COLLECTION_MONGO_CSL_COUNTRY,
|
||||
CM_CSL_DOB => COLLECTION_MONGO_CSL_DOB,
|
||||
CM_CSL_DOB_LIST => COLLECTION_MONGO_CSL_DOB_LIST,
|
||||
CM_CSL_FIRST_NAME => COLLECTION_MONGO_CSL_FN,
|
||||
CM_CSL_LAST_NAME => COLLECTION_MONGO_CSL_LN,
|
||||
CM_CSL_ID => COLLECTION_MONGO_CSL_ID,
|
||||
CM_CSL_ID_COUNTRY => COLLECTION_MONGO_CSL_ID_COUNTRY,
|
||||
CM_CSL_ID_LIST => COLLECTION_MONGO_CSL_ID_LIST,
|
||||
CM_CSL_ID_NUM => COLLECTION_MONGO_CSL_ID_NUMBER,
|
||||
CM_CSL_ID_TYPE => COLLECTION_MONGO_CSL_ID_TYPE,
|
||||
CM_CSL_MAIN_ENTRY => COLLECTION_MONGO_CSL_MAIN_ENTRY,
|
||||
CM_CSL_POB => COLLECTION_MONGO_CSL_POB,
|
||||
CM_CSL_POB_LIST => COLLECTION_MONGO_CSL_POB_LIST,
|
||||
CM_CSL_POST_CODE => COLLECTION_MONGO_CSL_POSTAL_CODE,
|
||||
CM_CSL_PRG => COLLECTION_MONGO_CSL_PRG,
|
||||
CM_CSL_PRG_LIST => COLLECTION_MONGO_CSL_PRG_LIST,
|
||||
CM_CSL_REM => COLLECTION_MONGO_CSL_REMARKS,
|
||||
CM_CSL_STATE_OR_PROVINCE => COLLECTION_MONGO_CSL_SOP,
|
||||
CM_CSL_TYPE => COLLECTION_MONGO_CSL_TYPE,
|
||||
CM_CSL_UID => COLLECTION_MONGO_CSL_UID,
|
||||
CM_CSL_SDN_TYPE => COLLECTION_MONGO_CSL_SDN_TYPE
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as the associative array: $exposedFields. Only those fields,
|
||||
* enumerated within this container, will be exposed to the client.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = [
|
||||
COLLECTION_MONGO_CSL_ADDR_LIST => [
|
||||
COLLECTION_MONGO_CSL_UID,
|
||||
COLLECTION_MONGO_CSL_ADDRESS1,
|
||||
COLLECTION_MONGO_CSL_ADDRESS2,
|
||||
COLLECTION_MONGO_CSL_ADDRESS3,
|
||||
COLLECTION_MONGO_CSL_CITY,
|
||||
COLLECTION_MONGO_CSL_POSTAL_CODE,
|
||||
COLLECTION_MONGO_CSL_COUNTRY,
|
||||
COLLECTION_MONGO_CSL_SOP
|
||||
],
|
||||
COLLECTION_MONGO_CSL_AKA_LIST => [
|
||||
COLLECTION_MONGO_CSL_UID,
|
||||
COLLECTION_MONGO_CSL_TYPE,
|
||||
COLLECTION_MONGO_CSL_CATEGORY,
|
||||
COLLECTION_MONGO_CSL_LN,
|
||||
COLLECTION_MONGO_CSL_FN
|
||||
],
|
||||
COLLECTION_MONGO_CSL_ID_LIST => [
|
||||
COLLECTION_MONGO_CSL_UID,
|
||||
COLLECTION_MONGO_CSL_ID_TYPE,
|
||||
COLLECTION_MONGO_CSL_ID_NUMBER
|
||||
]
|
||||
// COLLECTION_MONGO_CSL_DOB_LIST => [
|
||||
// COLLECTION_MONGO_CSL_UID,
|
||||
// COLLECTION_MONGO_CSL_DOB,
|
||||
// COLLECTION_MONGO_CSL_MAIN_ENTRY
|
||||
// ],
|
||||
// COLLECTION_MONGO_CSL_POB_LIST => [
|
||||
// COLLECTION_MONGO_CSL_UID,
|
||||
// COLLECTION_MONGO_CSL_POB,
|
||||
// COLLECTION_MONGO_CSL_MAIN_ENTRY
|
||||
// ],
|
||||
// COLLECTION_MONGO_CSL_PRG_LIST => [
|
||||
// COLLECTION_MONGO_CSL_PRG
|
||||
// ]
|
||||
];
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [OPERAND_NULL => [OPERATOR_LT => [null]]],
|
||||
DB_STATUS => [OPERAND_NULL => [OPERATOR_EQ => [STATUS_ACTIVE]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* Constructor in this template not only registers the shutdown method, but also allows us to generate a custom
|
||||
* GUID string during instantiation by use of the input parameters:
|
||||
*
|
||||
* $_getGUID - boolean, defaults to false but, if true, will generate a GUID value and store it in the class member
|
||||
* $_lc - boolean, defaults to false but, if true, will generate a GUID using lower-case alpha characters
|
||||
*
|
||||
* If we generate a GUID on instantiation, the GUID will be stored in the class member. This allows us to both
|
||||
* instantiate a session class object and a GUID value, (the most requested, post-instantiation, action), at the
|
||||
* same time. All the efficient.
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-03-20 mks DB-179: original coding
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* processCONSList() -- public template method
|
||||
*
|
||||
* This template method is accessible through the factory widget->template object only.
|
||||
*
|
||||
* The CONS list is available from the US Treasure Department and contains a list of Individuals and Entities
|
||||
* that have sanctions applied that prohibits the transfer of funds.
|
||||
*
|
||||
* The list, available at:
|
||||
* https://home.treasury.gov/policy-issues/financial-sanctions/consolidated-sanctions-list-data-files
|
||||
* and known as: consolidated.xml, contains the entire sanctions list.
|
||||
*
|
||||
* The format of the list is not conducive to efficient data storage so we're going to manipulate some of the
|
||||
* columnar elements, which are lists (arrays), s.t. we're removed the superflous and redundant sub-container
|
||||
* headers so that all lists are associative arrays of indexed arrays.
|
||||
*
|
||||
* The function requires the following input parameters:
|
||||
*
|
||||
* $_file - the fqfn file containing the CONS XML list
|
||||
* $_errs - a call-by-reference parameter that will return processing errors back to the calling client
|
||||
* $_lastUpdated - a call-by-reference parameter that returns the date when the list was updated last
|
||||
* $_recCount - a call-by-reference parameter containing the total number of records as report by USDoT
|
||||
*
|
||||
* On successful processing, the function returns an array, the processed cons list with the header removed
|
||||
* and the sub-arrays all nice and homogeneous.
|
||||
*
|
||||
* If there was an error raised in processing, we'll store a copy of the error in $_errs and return a null
|
||||
* value back to the calling client.
|
||||
*
|
||||
* If an exception is raised, a null will be returned and the error(s) logged to the db and to the console.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* @param string $_file
|
||||
* @param array|null $_errs
|
||||
* @param string $_lastUpdated
|
||||
* @param int $_recCount
|
||||
* @return array|null
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-07-20 mks DB-180: original coding
|
||||
*
|
||||
*/
|
||||
public function processCONSList(string $_file, ?array &$_errs, string &$_lastUpdated = '', int &$_recCount = 0): ?array
|
||||
{
|
||||
$method = basename(__METHOD__);
|
||||
$aryRetData = null;
|
||||
if (empty($_file)) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
$_errs[] = $hdr . ERROR_PARAM_404 . STRING_LIST;
|
||||
return null;
|
||||
}
|
||||
// see if we can open the file for reading
|
||||
$fp = simplexml_load_file($_file);
|
||||
if (false === $fp) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
$_errs[] = $hdr . ERROR_OPEN_XML_FILE . $_file;
|
||||
return null;
|
||||
} else {
|
||||
try {
|
||||
if (is_null($consData = objectToArray($fp))) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
$_errs[] = $hdr . ERROR_DATA_OBJ_2_ARY_FAIL;
|
||||
return null;
|
||||
}
|
||||
} catch (Throwable | TypeError $t) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $_errs, true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// at this point, we have successfully loaded the CONS XML file and have stored it, as an array, in $consData
|
||||
// we need to clean up the "lists" embedded as sub-arrays since they XML introduced an artificial layer
|
||||
// pointing to the data: $consData['sdnEntry']['akaList']['aka'][0, ..., n]
|
||||
// ^^^^^ <--- this is the layer to be removed
|
||||
$records = $consData[CONS_SDN_ENTRY];
|
||||
$consMeta = $consData[CONS_PUB_INFO];
|
||||
$_lastUpdated = $consMeta[CONS_PUB_DATE];
|
||||
$_recCount = intval($consMeta[CONS_REC_COUNT]);
|
||||
// list of list (entities) -- these are the sub-collections as opposed to sub-arrays
|
||||
$lol = [COLLECTION_MONGO_CSL_AKA_LIST => COLLECTION_MONGO_CSL_AKA,
|
||||
COLLECTION_MONGO_CSL_ADDR_LIST => COLLECTION_MONGO_CSL_ADDRESS,
|
||||
COLLECTION_MONGO_CSL_ID_LIST => COLLECTION_MONGO_CSL_ID,
|
||||
COLLECTION_MONGO_CSL_PRG_LIST => COLLECTION_MONGO_CSL_PRG,
|
||||
COLLECTION_MONGO_CSL_DOB_LIST => COLLECTION_MONGO_CSL_DOB_ITEM,
|
||||
COLLECTION_MONGO_CSL_POB_LIST => COLLECTION_MONGO_CSL_POB_ITEM
|
||||
];
|
||||
try {
|
||||
foreach ($records as &$record) {
|
||||
foreach ($record as $field => $fieldValue) {
|
||||
if (is_array($fieldValue) and array_key_exists($field, $lol)) {
|
||||
if (is_array($record[$field][$lol[$field]]) and is_numeric(key($record[$field][$lol[$field]]))) {
|
||||
// sub-array has multiple elements
|
||||
foreach ($record[$field][$lol[$field]] as $subRecord) {
|
||||
$record[$field][] = $subRecord;
|
||||
}
|
||||
} else {
|
||||
// sub-array has but a single element
|
||||
$record[$field][] = $record[$field][$lol[$field]];
|
||||
}
|
||||
unset($record[$field][$lol[$field]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable | TypeError $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $_errs, true);
|
||||
return null;
|
||||
}
|
||||
return $records;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* saveCONSList() -- public template method
|
||||
*
|
||||
* This method has the following input parameters:
|
||||
*
|
||||
* $_data -- this is the broker request data array
|
||||
* $_errs -- a call-by-reference parameter for returning processing errors back to the calling client
|
||||
*
|
||||
* The method will return a null value when there are errors in parsing the input parameters, or from saving
|
||||
* the XML file to disk.
|
||||
*
|
||||
* Otherwise, on success, the method returns the FQFN of the saved XML file.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_data
|
||||
* @param array|null $_errs
|
||||
* @return string|null
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-09-20 mks DB-180: original programming
|
||||
*
|
||||
*/
|
||||
public function saveCONSList(array $_data, ?array &$_errs): ?string
|
||||
{
|
||||
$method = basename(__METHOD__);
|
||||
if (empty($_data)) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
@handleExceptionMessaging($hdr, ERROR_DATA_ARRAY_EMPTY, $_errs, true);
|
||||
return null;
|
||||
}
|
||||
if (!is_array($_data)) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
@handleExceptionMessaging($hdr, ERROR_DATA_ARRAY_NOT_ARRAY . STRING_DATA, $_errs, true);
|
||||
return null;
|
||||
}
|
||||
if (!array_key_exists(STRING_DATA, $_data) or empty($_data[STRING_DATA])) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
@handleExceptionMessaging($hdr, ERROR_DATA_ARRAY_EMPTY . COLON . STRING_DATA, $_errs, true);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
// extract the XML file from the data payload
|
||||
$xmlFile = $_data[STRING_DATA];
|
||||
// write the file to tmp storage
|
||||
$guid = guid();
|
||||
$fqfn = DIR_TMP . SLASH . $guid . DOT . FILE_TYPE_XML;
|
||||
if (false === file_put_contents($fqfn, $xmlFile)) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
@handleExceptionMessaging($hdr, ERROR_SAVE_XML_FILE . $fqfn, $_errs, true);
|
||||
return null;
|
||||
}
|
||||
} catch (Throwable | TypeError $t) {
|
||||
$hdr = sprintf(INFO_LOC, $method, __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $_errs, true);
|
||||
return null;
|
||||
}
|
||||
return $fqfn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* cleanUp() -- public template method
|
||||
*
|
||||
* This file has a single, required, input parameter: the FQFN of the original XML file. Once validated, we'll
|
||||
* load the XML file into a variable and use that string as the VALUE value in the system-data table for row #2.
|
||||
*
|
||||
* This means that the last CONS list added to the Segundo collection has been stored (for archival and validation
|
||||
* purposes) as a flat-file in a column in a mongo table.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_file
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-15-20 mks DB-180: original coding
|
||||
*
|
||||
*/
|
||||
public function cleanUp(string $_file = ''):void
|
||||
{
|
||||
$errors = [];
|
||||
try {
|
||||
if (strlen($_file) and file_exists($_file)) {
|
||||
$contents = file_get_contents($_file);
|
||||
if (false === $contents) {
|
||||
consoleLog('CONS: ', CON_ERROR, ERROR_OPEN_XML_FILE . $_file);
|
||||
return;
|
||||
}
|
||||
// delete the XML file
|
||||
unlink($_file);
|
||||
|
||||
// instantiate a system-data widget
|
||||
$meta = [
|
||||
META_TEMPLATE => TEMPLATE_CLASS_SYS_DATA,
|
||||
META_CLIENT => CLIENT_SYSTEM,
|
||||
META_EVENT_GUID => guid()
|
||||
];
|
||||
/** @var gacMongoDB $widget */
|
||||
if (is_null($widget = grabWidget($meta, '', $errors))) {
|
||||
consoleLog('CONS: ', CON_ERROR, ERROR_FAILED_TO_INSTANTIATE . TEMPLATE_CLASS_SYS_DATA);
|
||||
} else {
|
||||
// save the XML data to the system-data table
|
||||
$data = [
|
||||
DATA_KEY => DATA_CONS,
|
||||
DATA_VALUE => $contents,
|
||||
ROW_ID => SYS_DATA_ROW_ID_CONS
|
||||
];
|
||||
$bc = new gacWorkQueueClient( basename(__METHOD__) . AT . __LINE__);
|
||||
if (!$bc->status) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, sprintf(ERROR_BROKER_CLIENT_INSTANTIATION, BROKER_QUEUE_AI, null, true));
|
||||
} else {
|
||||
$payload = [
|
||||
BROKER_REQUEST => BROKER_REQUEST_CREATE,
|
||||
BROKER_DATA => [$data],
|
||||
BROKER_META_DATA => $meta
|
||||
];
|
||||
if (false === $bc->call(gzcompress(json_encode($payload))))
|
||||
consoleLog('CONS: ', CON_ERROR, sprintf(ERROR_MDB_QUERY_FAIL, STRING_UPSERT));
|
||||
}
|
||||
if (is_object($bc)) $bc->__destruct();
|
||||
unset($bc);
|
||||
}
|
||||
}
|
||||
} catch (TypeError | Throwable $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__FILE__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $errors, true);
|
||||
}
|
||||
if (isset($widget) and is_object($widget)) {
|
||||
$widget->__destruct();
|
||||
unset($widget);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-03-20 mks DB-179: original coding
|
||||
*
|
||||
* @version 1.0
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-03-20 mks DB-179: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// blank
|
||||
}
|
||||
}
|
||||
450
classes/templates/gatDonors.class.inc
Normal file
450
classes/templates/gatDonors.class.inc
Normal file
@@ -0,0 +1,450 @@
|
||||
<?php
|
||||
/** @noinspection PhpUnused */
|
||||
|
||||
/**
|
||||
* Class gatDonors -- mongo data-template class
|
||||
*
|
||||
* This template defines the donors collection, part of the integrated partnerships sub-system.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-06-20 mks DB-147: original coding
|
||||
* 06-01-20 mks ECI-108: support for authToken
|
||||
*/
|
||||
|
||||
class gatDonors
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_APPSERVER; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_DONORS; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_DONORS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_DONORS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NONDESTRUCTIVE; // set to AUDIT_value constant (nondestructive = reads(yes))
|
||||
public bool $setJournaling = true; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = true; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = false; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique pkey exposed externally and is REQUIRED
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER, // epoch time
|
||||
DONORS_TRANS_COUNT => DATA_TYPE_INTEGER, // transaction count
|
||||
DONORS_DTCC => DATA_TYPE_INTEGER, // donations to current cause
|
||||
DONORS_TOTAL_DONATIONS => DATA_TYPE_DOUBLE, // dollar amount of total donations
|
||||
DONORS_SDWC => DATA_TYPE_BOOL, // share data with cause
|
||||
DONORS_CID => DATA_TYPE_STRING, // foreign key to somewhere
|
||||
DONORS_CAUSE_TITLE => DATA_TYPE_STRING,
|
||||
DONORS_UNK_FOREIGN_ID => DATA_TYPE_INTEGER // unknown generic foreign key
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, MONGO_ID
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_CREATED, DONORS_CID, DB_STATUS, DB_TOKEN
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_CREATED => -1,
|
||||
DONORS_CID => 1
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Sparse indexes only add the row to the index if the column referenced satisfies the conditions specified
|
||||
// in the query condition (expr2).
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1 // MONGO_TOKEN should always appear
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null; // ttl indexes appear in $indexFields
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
DB_TOKEN => CM_TST_TOKEN,
|
||||
DB_STATUS => CM_TST_FIELD_TEST_STATUS,
|
||||
DB_EVENT_GUID => CM_TST_EVENT_GUID,
|
||||
DB_CREATED => CM_TST_FIELD_TEST_CDATE,
|
||||
DB_ACCESSED => CM_TST_FIELD_TEST_ADATE,
|
||||
DONORS_TRANS_COUNT => CM_DONORS_TC,
|
||||
DONORS_DTCC => CM_DONORS_DTCC,
|
||||
DONORS_TOTAL_DONATIONS => CM_DONORS_TD,
|
||||
DONORS_SDWC => CM_DONORS_SDWC,
|
||||
DONORS_CID => CM_DONORS_CID,
|
||||
DONORS_CAUSE_TITLE => CM_DONORS_CT,
|
||||
DONORS_UNK_FOREIGN_ID => CM_DONORS_FI
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = null;
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [OPERAND_NULL => [OPERATOR_LT => [null]]],
|
||||
DB_STATUS => [OPERAND_NULL => [OPERATOR_EQ => [STATUS_ACTIVE]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-06-20 mks DB-147: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-06-20 mks DB-147: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-06-20 mks DB-147: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
459
classes/templates/gatFailedSessions.class.inc
Normal file
459
classes/templates/gatFailedSessions.class.inc
Normal file
@@ -0,0 +1,459 @@
|
||||
<?php
|
||||
/** @noinspection PhpUnused */
|
||||
|
||||
/**
|
||||
* Class gatFailedSessions -- mongo class
|
||||
*
|
||||
* This is an admin class that tracks failed session closures. Currently, this is limited to AT(1)-based events.
|
||||
* Entries in this collection allow us to trigger a batch job at night where we can have a second go at processing the
|
||||
* event requests that previously failed.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-13-20 mks DB-168: Original coding
|
||||
*/
|
||||
|
||||
class gatFailedSessions
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version; not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_TERCERO; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_FAILED_SESSIONS; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_FAILED_SESSIONS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_FAILED_SESSIONS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = false; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = false; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant (nondestructive = reads(yes))
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = false; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER, // epoch time
|
||||
// fields specific to systemEvents collection
|
||||
MONGO_FAILED_EVENT_GUID => DATA_TYPE_STRING,
|
||||
MONGO_FAILED_EVENT_NAME => DATA_TYPE_STRING,
|
||||
MONGO_FAILED_EVENT_DESC => DATA_TYPE_STRING,
|
||||
MONGO_FAILED_EVENT_SEV => DATA_TYPE_STRING,
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, DB_STATUS
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_CREATED, DB_EVENT_GUID, DB_ACCESSED, MONGO_ID, DB_STATUS
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_TOKEN, DB_CREATED, DB_STATUS, DB_EVENT_GUID,
|
||||
MONGO_FAILED_EVENT_GUID, MONGO_FAILED_EVENT_NAME, MONGO_FAILED_EVENT_SEV
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_TOKEN => 1,
|
||||
DB_CREATED => -1,
|
||||
DB_STATUS => 1,
|
||||
DB_EVENT_GUID => 1,
|
||||
MONGO_FAILED_EVENT_NAME => 1,
|
||||
MONGO_FAILED_EVENT_SEV => 1
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Sparse indexes only add the row to the index if the column referenced satisfies the conditions specified
|
||||
// in the query condition (expr2).
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1, // MONGO_TOKEN should always appear
|
||||
DB_EVENT_GUID => 1,
|
||||
MONGO_FAILED_EVENT_GUID => 1
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
// cache maps are required for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
DB_TOKEN => CM_TOKEN,
|
||||
DB_CREATED => CM_DATE_CREATED,
|
||||
DB_ACCESSED => CM_DATE_ACCESSED,
|
||||
DB_STATUS => CM_STATUS,
|
||||
DB_EVENT_GUID => CM_EVENT_GUID,
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as the associative array: $exposedFields. Only those fields,
|
||||
* enumerated within this container, will be exposed to the client.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = null;
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [OPERAND_NULL => [OPERATOR_LT => [null]]],
|
||||
DB_STATUS => [OPERAND_NULL => [OPERATOR_EQ => [STATUS_ACTIVE]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-13-20 mks DB-169: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* Constructor in this template not only registers the shutdown method, but also allows us to generate a custom
|
||||
* GUID string during instantiation by use of the input parameters:
|
||||
*
|
||||
* $_getGUID - boolean, defaults to false but, if true, will generate a GUID value and store it in the class member
|
||||
* $_lc - boolean, defaults to false but, if true, will generate a GUID using lower-case alpha characters
|
||||
*
|
||||
* If we generate a GUID on instantiation, the GUID will be stored in the class member. This allows us to both
|
||||
* instantiate a session class object and a GUID value, (the most requested, post-instantiation, action), at the
|
||||
* same time. All the efficient.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-13-20 mks DB-169: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-13-20 mks DB-169: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// move on lookie-loo....
|
||||
}
|
||||
|
||||
}
|
||||
458
classes/templates/gatGraphs.class.inc
Normal file
458
classes/templates/gatGraphs.class.inc
Normal file
@@ -0,0 +1,458 @@
|
||||
<?php
|
||||
/**
|
||||
* Class gatGraphs
|
||||
*
|
||||
* This is the class used for feeding the Namaste graphing dashboard.
|
||||
*
|
||||
* Design Notes:
|
||||
* -------------
|
||||
* The graphs collection is designed to be "open" with respect to the data captured. Graphs was originally intended
|
||||
* to be a time-series based collection. However, I wanted to expand the definition to include almost any type of
|
||||
* data.
|
||||
*
|
||||
* The main columns are the ones labeled key and value. These are the pivotal columns - the key defines the name of
|
||||
* data element, and value defines the metric value.
|
||||
*
|
||||
* For example, if I was graphing query metrics, I would receive a key of 'queryTime' and a value of 0.089. Combined
|
||||
* with the date/time field, I could submit this data as time-series. However, the key "queryTime" represents an
|
||||
* arbitrary event as we don't know which query this was measured against, what schema, etc.
|
||||
*
|
||||
* The remaining fields, then, help narrow the scope of the event.
|
||||
*
|
||||
* Another example, this time working the other way, is that I want to record the number of event requests that are
|
||||
* being received by the brokers.
|
||||
*
|
||||
* I could use a key of 'brokerEvent', with the value being the time the event took to process. Supporting values may
|
||||
* include service, broker, and event so that we now which service the event was processed on, which broker on that
|
||||
* service processed the event, and which event was processed. This combination of data allows us to start building
|
||||
* a history of efficiency of a particular service, broker or event.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-29-19 mks DB-136: original coding
|
||||
* 01-13-20 mks DB-150: PHP7.4 member type-casting
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
|
||||
class gatGraphs
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1;
|
||||
public string $service = CONFIG_DATABASE_SERVICE_ADMIN; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_GRAPHS; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_GRAPHS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_GRAPHS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = false; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to enable journaling
|
||||
public bool $setUpdates = false; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = false; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 0; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
GRAPH_KEY => DATA_TYPE_STRING, // primary value: the metric being recorded
|
||||
GRAPH_VALUE => DATA_TYPE_MIXED, // primary value: the value of the metric
|
||||
GRAPH_SCHEMA => DATA_TYPE_STRING, // (optional) what was the db schema?
|
||||
GRAPH_SERVICE => DATA_TYPE_STRING, // (optional) what service handled the event?
|
||||
GRAPH_LOCATION => DATA_TYPE_ARRAY, // array containing file:method:line info
|
||||
GRAPH_FILE => DATA_TYPE_STRING, // sub-array label for the file
|
||||
GRAPH_METHOD => DATA_TYPE_STRING, // sub-array label for the method
|
||||
GRAPH_LINE => DATA_TYPE_INTEGER, // sub-array label for the line
|
||||
GRAPH_COMMENT => DATA_TYPE_STRING, // (optional) free-form text description
|
||||
GRAPH_LABEL => DATA_TYPE_STRING, // (optional) suggestion for a graph label
|
||||
GRAPH_COLLECTION => DATA_TYPE_STRING, // (optional) the db collection involved
|
||||
GRAPH_DBO => DATA_TYPE_STRING, // (optional) the database object involved
|
||||
GRAPH_EVENT => DATA_TYPE_STRING, // (optional) the name of the broker event
|
||||
GRAPH_BROKER => DATA_TYPE_STRING, // (optional) the name of the broker
|
||||
GRAPH_TIMER => DATA_TYPE_DOUBLE, // (optional) timer values go here because double
|
||||
GRAPH_DATE => DATA_TYPE_DATETIME, // (optional) cleartext data because grafana likes 'em
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (string) exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER // epoch time
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [MONGO_ID, GRAPH_KEY, GRAPH_SERVICE, GRAPH_COLLECTION, GRAPH_DBO,
|
||||
GRAPH_EVENT, GRAPH_BROKER, DB_TOKEN, DB_EVENT_GUID, DB_CREATED ];
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_CREATED => -1,
|
||||
DB_TOKEN => 1,
|
||||
GRAPH_KEY => 1
|
||||
];
|
||||
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = [ 'graphServiceIDX', 'graphBrokerIDX' ];
|
||||
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = [
|
||||
'graphServiceIDX' => [ GRAPH_SERVICE => 1, GRAPH_COLLECTION => 1, GRAPH_DBO => 1 ],
|
||||
'graphBrokerIDX' => [ GRAPH_BROKER => 1, GRAPH_EVENT => 1 ]
|
||||
];
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = null; // token is not required for system collections
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null; // ttl indexes appear in $indexFields
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = null; // key-value paired array of field-names mapped to cache-names
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null; // lists the fields that will be sent to clients; null => all data
|
||||
// cache map, if defined, will always override.
|
||||
// mongo IDs are NEVER returned
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = null; // sub-collection fields must be declared here
|
||||
// see gatTestMongo.class.inc for explanation & examples
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [OPERAND_NULL => [OPERATOR_LT => [null]]],
|
||||
DB_STATUS => [OPERAND_NULL => [OPERATOR_EQ => [STATUS_ACTIVE]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-29-19 mks DB-136: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-29-19 mks DB-136: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-29-19 mks DB-136: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
593
classes/templates/gatJournaling.class.inc
Normal file
593
classes/templates/gatJournaling.class.inc
Normal file
@@ -0,0 +1,593 @@
|
||||
<?php
|
||||
/**
|
||||
* gatJournaling.class.inc -- mongo template class
|
||||
*
|
||||
* This template defines the journaling collection - a Namaste subsystem that bestows point-in-time recovery
|
||||
* at the record level for supported data classes.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-16-18 mks DB-57: original coding
|
||||
* 02-07-19 mks DB-115: JOURNAL_AUD_TOK is now a unique indexed field
|
||||
* 01-13-20 msk DB-150: PHP7.4 class member type-casting
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
|
||||
class gatJournaling
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_ADMIN; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_JOURNAL; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_JOURNAL; // sets the collection (table) name
|
||||
public ?string $whTemplate = TEMPLATE_CLASS_JOURNAL; // name of the warehouse template (not collection)
|
||||
public string $extension = COLLECTION_MONGO_JOURNAL_EXT;// sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = false; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
// fields specific to the collection
|
||||
MONGO_ID => DATA_TYPE_OBJECT, // sorting by the id is just like sorting by createdDate
|
||||
JOURNAL_SYSEV_TOK => DATA_TYPE_STRING, // systemEvent GUID
|
||||
JOURNAL_AUD_TOK => DATA_TYPE_STRING, // audit GUID
|
||||
JOURNAL_RECORD_GUID => DATA_TYPE_STRING, // GUID of the change record (table data in audit rec)
|
||||
JOURNAL_RESTORE_QUERY => DATA_TYPE_STRING, // Namaste-derived query to restore the record
|
||||
JOURNAL_HISTORY => DATA_TYPE_ARRAY, // sub-collection containing the journal-access history
|
||||
JOURNAL_HISTORY_DATE_RESTORED => DATA_TYPE_STRING, // sub-collection field: date record restored
|
||||
JOURNAL_HISTORY_RESTORED_EVENT_GUID => DATA_TYPE_STRING, // sub-collection field: restore request event GUID
|
||||
JOURNAL_HISTORY_RESTORED_BY => DATA_TYPE_STRING, // sub-collection field: name/GUID requesting user
|
||||
JOURNAL_HISTORY_RESTORED_REASON => DATA_TYPE_STRING, // sub-collection field: client supplied text
|
||||
// generic mongo constants
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (string) exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER // epoch time
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
// todo -- code a condition where ALL fields are protected using the * symbol (DB-58)
|
||||
public ?array $protectedFields = [
|
||||
MONGO_ID, JOURNAL_SYSEV_TOK, JOURNAL_RESTORE_QUERY, JOURNAL_HISTORY, JOURNAL_AUD_TOK,
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_STATUS, DB_ACCESSED, JOURNAL_RECORD_GUID
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_CREATED, DB_TOKEN, DB_ACCESSED, JOURNAL_RECORD_GUID, JOURNAL_AUD_TOK,
|
||||
JOURNAL_SYSEV_TOK, DB_EVENT_GUID
|
||||
];
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_CREATED => -1, // assuming we want LIFO
|
||||
DB_ACCESSED => -1, // assuming we want LIFO
|
||||
DB_EVENT_GUID => 1, // event guid should always be indexed
|
||||
JOURNAL_RECORD_GUID => 1
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1, // MONGO_TOKEN should always appear
|
||||
JOURNAL_SYSEV_TOK => 1,
|
||||
JOURNAL_AUD_TOK => 1 // Journal -> Audit is 1:1 so this key must be unique
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = null;
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
* SubC fields do not need to be indexed.
|
||||
*
|
||||
*/
|
||||
public ?array $subC = [
|
||||
JOURNAL_HISTORY => [
|
||||
JOURNAL_HISTORY_DATE_RESTORED,
|
||||
JOURNAL_HISTORY_RESTORED_BY,
|
||||
JOURNAL_HISTORY_RESTORED_EVENT_GUID,
|
||||
JOURNAL_HISTORY_RESTORED_REASON
|
||||
]
|
||||
];
|
||||
|
||||
//=================================================================================================================
|
||||
// MIGRATION DECLARATIONS
|
||||
// ----------------------
|
||||
// Data in this section is used to handle migrations -- when we're pulling from legacy tables into the Namaste
|
||||
// framework. See online doc for more info.
|
||||
//=================================================================================================================
|
||||
|
||||
/**
|
||||
* The migration map is an associative array that maps the Namaste fields (keys) to the corresponding
|
||||
* (remote) legacy fields in the source table to be migrated to Namaste.
|
||||
*
|
||||
* For example, if we were migrating a mysql table in the legacy production database to Namaste::mongo, then
|
||||
* the keys of the migration map would be the Namaste::mongo->fieldNames and the values would be the mysql
|
||||
* column names in the legacy table.
|
||||
*
|
||||
* If there is a value which cannot be mapped to a key, then set it to null.
|
||||
*
|
||||
* Fields that will be dropped in the migration are not listed as values or as keys.
|
||||
*
|
||||
* This map will only exist in the template object and will never be imported into the class widget.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationMap = null;
|
||||
|
||||
/*
|
||||
* the migrationSortKey defines the SOURCE field by which the fetch query will be sorted. ALL sort fields are
|
||||
* in ASC order so all we need to list here is the name of the field -- which MUST BE IN THE SOURCE TABLE.
|
||||
*
|
||||
* Populating this field may require preliminary examination of the data - what we want is a field that has
|
||||
* zero NULL values.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationSortKey = null;
|
||||
|
||||
/*
|
||||
* The migrationStatusKey defines the status field/column in the source table -- if the user requires that
|
||||
* soft-deleted records not be migrated, then this field must be set. Otherwise, set the value to null.
|
||||
*
|
||||
* The format is in the form of a key-value paired array. The key specifies the name of the column and the value
|
||||
* specifies the "deleted" value that, if found, will cause that row from the SOURCE data to be omitted from the
|
||||
* DESTINATION table.
|
||||
*
|
||||
* e.g.: $migrationStatusKV = [ 'some_field' => 'deleted' ]
|
||||
*
|
||||
* Note that both the key and the value are case-sensitive!
|
||||
*
|
||||
* This is an optional field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationStatusKV = null;
|
||||
|
||||
// The $migrationSourceSchema defines the remote schema for the source table
|
||||
public ?string $migrationSourceSchema = null; // or STRING_MONGO
|
||||
|
||||
// The source table in the remote repos (default defined in the XML) must be declared here
|
||||
public ?string $migrationSourceTable = null;
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => true, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'Q', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => true, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
WH_INDEXES => [DB_CREATED, DB_WH_CREATED],
|
||||
WH_TEMPLATE => '',
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [ OPERAND_NULL => [ OPERATOR_LT => [ null ] ] ],
|
||||
DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-16-18 mks DB-57: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}/** @noinspection PhpUnused */
|
||||
|
||||
|
||||
/**
|
||||
* buildJournalData() -- template method
|
||||
*
|
||||
* This template method should only be called from the AdminIN broker when creating a journal record. It's sole
|
||||
* purpose is to build the data payload (record) that will be saved to the mongo database. As such, there are
|
||||
* four input parameters to the method:
|
||||
*
|
||||
* $_sysEvTok -- string value containing the system event token value
|
||||
* $_audTok -- string value containing the audit event token value
|
||||
* $_journalData -- indexed array containing two associative arrays containing the recovery queries and token list
|
||||
* $_es -- call-by-reference array parameter used to send error messages back to the calling client
|
||||
*
|
||||
* Processing errors will be raised if any of the first three input values are missing or invalid. Also, we compare
|
||||
* the count of the the number of elements in the $_journalData array -- this array should have to keys:
|
||||
* STRING_JOURNAL_TOKEN_LIST and STRING_JOURNAL_QUERY_LIST and the same number of elements must be in both.
|
||||
*
|
||||
* If errors are encountered during processing, then an error message is returned (implicitly) and a null value is
|
||||
* explicitly returned to the caller.
|
||||
*
|
||||
* Otherwise, we return an indexed array of records that will be inserted into the journal collection.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_sysEvTok
|
||||
* @param string $_audTok
|
||||
* @param array $_journalData
|
||||
* @param array $_es
|
||||
* @return array|null
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-25-18 mks DB-74: original coding
|
||||
*
|
||||
*/
|
||||
public function buildJournalData(string $_sysEvTok, string $_audTok, array $_journalData, array &$_es): ?array
|
||||
{
|
||||
$res = 'JRNL: ';
|
||||
$data = null;
|
||||
if (!validateGUID($_sysEvTok)) {
|
||||
$msg = ERROR_INVALID_GUID . $_sysEvTok;
|
||||
consoleLog($res, CON_SYSTEM, $msg);
|
||||
$_es[] = $msg;
|
||||
return $data;
|
||||
}
|
||||
if (!validateGUID($_audTok)) {
|
||||
$msg = ERROR_INVALID_GUID . $_audTok;
|
||||
consoleLog($res, CON_SYSTEM, $msg);
|
||||
$_es[] = $msg;
|
||||
return $data;
|
||||
}
|
||||
if (count($_journalData[STRING_JOURNAL_QUERY_LIST]) < 1 or count($_journalData[STRING_JOURNAL_QUERY_LIST]) != count($_journalData[STRING_JOURNAL_TOKEN_LIST])) {
|
||||
$msg = ERROR_AUDIT_COUNT;
|
||||
consoleLog($res, CON_SYSTEM, $msg);
|
||||
$_es[] = $msg;
|
||||
return $data;
|
||||
}
|
||||
for ($i = 0, $max = count($_journalData[STRING_JOURNAL_TOKEN_LIST]); $i < $max; $i++) {
|
||||
$data[$i][JOURNAL_SYSEV_TOK] = $_sysEvTok;
|
||||
$data[$i][JOURNAL_AUD_TOK] = $_audTok;
|
||||
$data[$i][JOURNAL_RECORD_GUID] = $_journalData[STRING_JOURNAL_TOKEN_LIST][$i];
|
||||
$data[$i][JOURNAL_RESTORE_QUERY] = $_journalData[STRING_JOURNAL_QUERY_LIST][$i];
|
||||
}
|
||||
consoleLog($res, CON_SUCCESS, sprintf(STUB_PROCESSED, $max, STRING_JOURNAL));
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-16-18 mks DB-57: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-16-18 mks DB-57: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
434
classes/templates/gatLogs.class.inc
Normal file
434
classes/templates/gatLogs.class.inc
Normal file
@@ -0,0 +1,434 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class gatLog
|
||||
*
|
||||
* This is the logging class definition that records application-generated events.
|
||||
*
|
||||
* Design Notes:
|
||||
* -------------
|
||||
* because this is a log, and log events are processed by a FnF queue, we're not going to cache, or use auditing.
|
||||
* History is not recorded for this class.
|
||||
* Only one status is supported: ACTIVE and there are no updates allowed making record-locking unnecessary.
|
||||
* Cache timers on the class are disabled because recursion.
|
||||
* id's (auto-incrementing integers) are deprecated and replaced by the native _id.
|
||||
* The created date is stored an epoch time (integer).
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-06-17 mks CORE-463: code complete (refactor from ddb to mdb)
|
||||
* 07-12-17 mks added log-level value column to collection for ranged searching
|
||||
* 08-04-17 mks added version control, partialIndexes
|
||||
* 08-11-17 mks CORE-467: indexes brought up to mongo 3.2 standards and made consistent
|
||||
* 04-19-18 mks _INF-188: warehousing section added
|
||||
* 01-13-20 mks DB-150: PHP7.4 class member type-casting
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
class gatLogs {
|
||||
public int $version = 1;
|
||||
public string $service = CONFIG_DATABASE_SERVICE_ADMIN; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_LOGS; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_LOGS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_LOGS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = false; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = false; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = false; // set to true to enable collection query timers
|
||||
public string $setPKey = MONGO_ID; // sets the primary key for the collection
|
||||
public bool $setTokens = false; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = true; // set to false if the class contains methods
|
||||
public int $cacheTimer = 0; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_OBJECT, // sorting by the id is just like sorting by createdDate
|
||||
LOG_FILE => DATA_TYPE_STRING,
|
||||
LOG_METHOD => DATA_TYPE_STRING,
|
||||
LOG_LINE => DATA_TYPE_INTEGER,
|
||||
LOG_CLASS => DATA_TYPE_STRING,
|
||||
LOG_LEVEL => DATA_TYPE_STRING,
|
||||
LOG_VALUE => DATA_TYPE_INTEGER,
|
||||
LOG_MESSAGE => DATA_TYPE_STRING,
|
||||
DB_STATUS => DATA_TYPE_STRING,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING,
|
||||
LOG_CREATED => DATA_TYPE_INTEGER
|
||||
];
|
||||
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [ MONGO_ID, LOG_CREATED, LOG_VALUE, LOG_FILE, LOG_LEVEL, DB_EVENT_GUID ];
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
LOG_CREATED => -1,
|
||||
LOG_VALUE => 1,
|
||||
LOG_FILE => 1,
|
||||
LOG_LEVEL => 1,
|
||||
DB_EVENT_GUID => 1
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = null; // token is not required for system collections
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null; // ttl indexes appear in $indexFields
|
||||
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null; // lists the fields that will be sent to clients; null => all data
|
||||
// cache map, if defined, will always override.
|
||||
// mongo IDs are NEVER returned
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = null; // sub-collection fields must be declared here
|
||||
// see gatTestMongo.class.inc for explanation & examples
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [ OPERAND_NULL => [ OPERATOR_LT => [ null ] ] ],
|
||||
DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-06-17 mks CORE-463: code complete (refactor from ddb to mdb)
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-06-17 mks CORE-463: code complete (refactor from ddb to mdb)
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-06-17 mks CORE-463: code complete (refactor from ddb to mdb)
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
433
classes/templates/gatMetrics.class.inc
Normal file
433
classes/templates/gatMetrics.class.inc
Normal file
@@ -0,0 +1,433 @@
|
||||
<?php /** @noinspection PhpUnused */
|
||||
|
||||
/**
|
||||
* Class gatMetrics
|
||||
*
|
||||
* This is the metrics class definition that records timer events, usually database queries.
|
||||
*
|
||||
* Design Notes:
|
||||
* -------------
|
||||
* Metrics is identical to Logs, who's events are processed by a FnF queue, we're not going to cache, or use auditing.
|
||||
* History is not recorded for this class.
|
||||
* Only one status is supported: ACTIVE and there are no updates allowed making record-locking unnecessary.
|
||||
* Cache timers on the class are disabled because recursion.
|
||||
* id's (auto-incrementing integers) are deprecated and replaced by the native _id.
|
||||
* The created date is stored an epoch time (integer).
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-06-17 mks CORE-463: code complete (refactor from ddb to mdb)
|
||||
* 08-04-17 mks added version control, partialIndexes
|
||||
* 08-11-17 mks CORE-467: indexes brought up to mongo 3.2 standards and made consistent
|
||||
* 04-19-18 mks _INF-188: warehousing section added
|
||||
* 11-04-19 mks DB-136: Added DB_TIMER single-field index to indexFields container
|
||||
* 01-13-20 mks DB-150: PHP7.4 class member type-casting
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
class gatMetrics
|
||||
{
|
||||
public int $version = 1;
|
||||
public string $service = CONFIG_DATABASE_SERVICE_ADMIN; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_METRICS; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_METRICS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_METRICS_EXT;// sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = false; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to enable journaling
|
||||
public bool $setUpdates = false; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = false; // set to true to enable collection query timers
|
||||
public string $setPKey = MONGO_ID; // sets the primary key for the collection
|
||||
public bool $setTokens = false; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = true; // set to false if the class contains methods
|
||||
public int $cacheTimer = 0; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
LOG_FILE => DATA_TYPE_STRING,
|
||||
LOG_METHOD => DATA_TYPE_STRING,
|
||||
LOG_LINE => DATA_TYPE_INTEGER,
|
||||
LOG_CLASS => DATA_TYPE_STRING,
|
||||
LOG_LEVEL => DATA_TYPE_STRING,
|
||||
LOG_MESSAGE => DATA_TYPE_STRING,
|
||||
DB_STATUS => DATA_TYPE_STRING,
|
||||
DB_TIMER => DATA_TYPE_DOUBLE,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING,
|
||||
LOG_CREATED => DATA_TYPE_INTEGER
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [ MONGO_ID, LOG_CREATED, LOG_LEVEL, DB_EVENT_GUID, DB_TIMER ];
|
||||
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
LOG_CREATED => -1,
|
||||
LOG_LEVEL => 1,
|
||||
DB_EVENT_GUID => 1,
|
||||
DB_TIMER => -1
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = null; // token is not required for system collections
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null; // ttl indexes appear in $indexFields
|
||||
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = null; // key-value paired array of field-names mapped to cache-names
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null; // lists the fields that will be sent to clients; null => all data
|
||||
// cache map, if defined, will always override.
|
||||
// mongo IDs are NEVER returned
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = null; // sub-collection fields must be declared here
|
||||
// see gatTestMongo.class.inc for explanation & examples
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [ OPERAND_NULL => [ OPERATOR_LT => [ null ] ] ],
|
||||
DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-06-17 mks CORE-463: code complete (refactor from ddb to mdb)
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-06-17 mks CORE-463: code complete (refactor from ddb to mdb)
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-06-17 mks CORE-463: code complete (refactor from ddb to mdb)
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
471
classes/templates/gatMigrations.class.inc
Normal file
471
classes/templates/gatMigrations.class.inc
Normal file
@@ -0,0 +1,471 @@
|
||||
<?php
|
||||
/**
|
||||
* gatMigrations -- mongo template class
|
||||
*
|
||||
* This template is used internally to record migration process for a source table to it's destination. This table
|
||||
* records the new records created so that, in the event of failure, we can back-out the newly-created records from
|
||||
* the mongo collection.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 01-30-18 mks _INF-139: original coding
|
||||
* 04-19-18 mks _INF-188: warehousing section added
|
||||
* 11-04-19 mks DB-136: added missing DB_EVENT_GUID index to $indexFields
|
||||
* 01-13-20 mks DB-150: PHP7.4 member class type-casting
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*/
|
||||
|
||||
class gatMigrations
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_ADMIN; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_MIGRATIONS; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_MIGRATIONS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_MIGRATIONS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = false; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = false; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 0; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
MWH_SOURCE_SCHEMA => DATA_TYPE_STRING, // name of the source schema
|
||||
MWH_SOURCE_TABLE => DATA_TYPE_STRING, // name of the source table
|
||||
MWH_DEST_SCHEMA => DATA_TYPE_STRING, // name of the destination schema
|
||||
MWH_DEST_TABLE => DATA_TYPE_STRING, // name of the destination table
|
||||
MWH_QUERY => DATA_TYPE_STRING, // (first) query used to migrate the data
|
||||
MWH_DATE_STARTED => DATA_TYPE_INTEGER, // when the migration started (epoch time)
|
||||
MWH_NUM_RECS_SOURCE => DATA_TYPE_STRING, // number of records in the source table
|
||||
MWH_NUM_RECS_MOVED => DATA_TYPE_INTEGER, // number of records migrated
|
||||
MWH_NUM_RECS_DROPPED => DATA_TYPE_INTEGER, // number of records that were dropped
|
||||
MWH_LAST_REC_WRITTEN => DATA_TYPE_STRING, // json-encoded string of the last record written
|
||||
MWH_DATE_COMPLETED => DATA_TYPE_INTEGER, // when migration completed (epoch time)
|
||||
MWH_STOP_REASON => DATA_TYPE_STRING, // reason why migration failed
|
||||
MWH_ERROR_CAT => DATA_TYPE_ARRAY, // array of errors
|
||||
MWH_REPORT => DATA_TYPE_STRING, // stores the generated wh report
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (GUID) exposed externally and is REQUIRED
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER // epoch time
|
||||
];
|
||||
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, MONGO_ID, MWH_SOURCE_SCHEMA,
|
||||
MWH_SOURCE_TABLE, MIGRATION_DEST_SCHEMA, MIGRATION_DEST_TABLE,
|
||||
MWH_NUM_RECS_SOURCE, MWH_DATE_STARTED
|
||||
];
|
||||
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_CREATED, DB_TOKEN, MWH_SOURCE_TABLE, DB_STATUS, MWH_DEST_TABLE,
|
||||
MWH_DEST_SCHEMA, MWH_SOURCE_SCHEMA, DB_EVENT_GUID
|
||||
];
|
||||
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_CREATED => 1,
|
||||
DB_STATUS => 1,
|
||||
DB_EVENT_GUID => 1,
|
||||
MWH_SOURCE_TABLE => 1,
|
||||
MWH_DEST_TABLE => 1,
|
||||
MWH_DEST_SCHEMA => 1,
|
||||
MWH_SOURCE_SCHEMA => 1
|
||||
];
|
||||
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1 // MONGO_TOKEN should always appear
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = null; // todo -- test this setting
|
||||
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
* SubC fields do not need to be indexed.
|
||||
*
|
||||
*/
|
||||
public ?array $subC = null;
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [ OPERAND_NULL => [ OPERATOR_LT => [ null ] ] ],
|
||||
DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 01-30-18 mks _INF-139: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 01-30-18 mks _INF-139: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 01-30-18 mks _INF-139: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
655
classes/templates/gatProdRegistrations.class.inc
Normal file
655
classes/templates/gatProdRegistrations.class.inc
Normal file
@@ -0,0 +1,655 @@
|
||||
<?php
|
||||
/**
|
||||
* gatProdRegistrations.class -- Namaste mySQL Data Template
|
||||
*
|
||||
* This is the template file for the Namaste mySQL version of product-registration. This template was created for the
|
||||
* purpose of testing mysql->mysql data migration.
|
||||
*
|
||||
* There is another prod-reg template: gatProductRegistrations.class.inc -- which is a mongo data template.
|
||||
*
|
||||
* Once version 1.0.0 of Namaste is launched, please remember to deprecate either this, or the other, template class
|
||||
* so that there is no potential for confusion.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-23-18 mks CORE-852: original coding
|
||||
* 04-18-18 mks _INF-188: warehousing section added
|
||||
* 06-12-18 mks CORE-1043: updated PDO objects to add SQL statements for table create, update
|
||||
* 01-13-20 mks DB-150: PHP7.4 class member type-casting
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
|
||||
class gatProdRegistrations
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
public int $version = 1; // template version: not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_APPSERVER; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_PDO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_PROD_REGS; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_PDO_PROD_REGS; // sets the collection (table) name
|
||||
public ?string $whTemplate = TEMPLATE_CLASS_WHC1_PROD_REG; // name of the warehouse template (not collection)
|
||||
public string $extension = COLLECTION_PDO_PROD_REGS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = false; // set to true to cache class data
|
||||
public bool $setDeletes = false; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set 2 true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if class contains methods or migration
|
||||
public int $cacheTimer = 0; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = false; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
//
|
||||
// Note that for PDO-type tables, the data type is more ... homogeneous... e.g.: data types define the data
|
||||
// type only. It does not define the actual column type in-use. For example, there is no distinction made
|
||||
// between a tinyInt, Int, or BigInt. As far as the framework is concerned, they're all just integers.
|
||||
//
|
||||
public array $fields = [
|
||||
PDO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
PRG_TYPE => DATA_TYPE_STRING,
|
||||
PRG_IID => DATA_TYPE_STRING,
|
||||
PRG_EAV => DATA_TYPE_STRING,
|
||||
PRG_PLATFORM => DATA_TYPE_STRING,
|
||||
PRG_BROWSER => DATA_TYPE_STRING,
|
||||
PRG_MAJOR_VERSION => DATA_TYPE_INTEGER,
|
||||
PRG_MINOR_VERSION => DATA_TYPE_INTEGER,
|
||||
PRG_IS_MOBILE => DATA_TYPE_INTEGER,
|
||||
PRG_IS_TABLET => DATA_TYPE_INTEGER,
|
||||
PRG_FIRST_SEEN => DATA_TYPE_STRING,
|
||||
PRG_LAST_SEEN => DATA_TYPE_STRING,
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (string) exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_STRING, // dateTime type
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_STRING // dateTime type
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, PDO_ID
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public array $indexFields = [
|
||||
PDO_ID => 1,
|
||||
PRG_EAV => 1,
|
||||
PRG_IID => 1,
|
||||
PRG_TYPE => 1,
|
||||
DB_CREATED => 1,
|
||||
DB_STATUS => 1, // status should only be indexed if soft-deletes are enabled (just saying)
|
||||
DB_EVENT_GUID => 1, // event guid should always be indexed
|
||||
DB_TOKEN => 1
|
||||
];
|
||||
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = [ 'cIdx1Test'];
|
||||
|
||||
|
||||
// the primary key index is declared in the class properties section as $setPKey
|
||||
|
||||
// unique indexes are to be used a values stored in these columns have to be unique to the table. Note that
|
||||
// null values are permissible in unique-index columns. Do not declare MONGO_ID here, regardless of how badly
|
||||
// you may want to.
|
||||
public ?array $uniqueIndexes = [ DB_TOKEN => 1 ];
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index (index, multi)
|
||||
// the format for the single-field index declaration is a simple indexed array.
|
||||
public ?array $singleFields = [
|
||||
PRG_EAV, PRG_IID, PRG_TYPE, DB_EVENT_GUID
|
||||
];
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $compoundIndexes = [
|
||||
'cIdx1Test' => [ DB_CREATED, DB_STATUS ]
|
||||
];
|
||||
|
||||
|
||||
// NOTE: foreign-key indexes are not explicitly enumerated in a template -- that relationship is defined in the
|
||||
// schema for the table. Foreign-key indexes appear implicitly in the indexing declarations above.
|
||||
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
PRG_TYPE => CM_PRG_TYPE,
|
||||
PRG_IID => CM_PRG_IID,
|
||||
PRG_EAV => CM_PRG_EAV,
|
||||
PRG_PLATFORM => CM_PRG_PLATFORM,
|
||||
PRG_BROWSER => CM_PRG_BROWSER,
|
||||
PRG_MAJOR_VERSION => CM_PRG_MAJ_VER,
|
||||
PRG_MINOR_VERSION => CM_PRG_MIN_VER,
|
||||
PRG_IS_MOBILE => CM_PRG_IS_MOBILE,
|
||||
PRG_IS_TABLET => CM_PRG_IS_TABLET,
|
||||
PRG_FIRST_SEEN => CM_PRG_FIRST_SEEN,
|
||||
PRG_LAST_SEEN => CM_PRG_LAST_SEEN,
|
||||
DB_TOKEN => CM_TST_TOKEN,
|
||||
DB_STATUS => CM_TST_FIELD_TEST_STATUS,
|
||||
DB_EVENT_GUID => CM_TST_EVENT_GUID,
|
||||
DB_CREATED => CM_TST_FIELD_TEST_CDATE,
|
||||
DB_ACCESSED => CM_TST_FIELD_TEST_ADATE
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it a null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = [
|
||||
PRG_TYPE => 1,
|
||||
PRG_IID => 1,
|
||||
PRG_EAV => 1,
|
||||
PRG_PLATFORM => 1,
|
||||
PRG_BROWSER => 1,
|
||||
PRG_MAJOR_VERSION => 1,
|
||||
PRG_MINOR_VERSION => 1,
|
||||
PRG_IS_MOBILE => 1,
|
||||
PRG_IS_TABLET => 1,
|
||||
PRG_FIRST_SEEN => 1,
|
||||
PRG_LAST_SEEN => 1,
|
||||
DB_TOKEN => 1,
|
||||
DB_CREATED => 1, // epoch time
|
||||
DB_STATUS => 1, // record status
|
||||
DB_ACCESSED => 1 // epoch time
|
||||
];
|
||||
|
||||
// in PDO-land, binary fields are your basic data blobs. All binary fields require special handling and so
|
||||
// need to be enumerated here as an indexed array.
|
||||
public ?array $binFields = null;
|
||||
|
||||
|
||||
// DB SQL:
|
||||
// -------
|
||||
// PDO SQL is stored in the template and is keyed by the current namaste version (defined in the XML file) during
|
||||
// execution of the deployment script. Each version denotes a container of SQL commands that will be executed
|
||||
// for the targeted version.
|
||||
//
|
||||
// SQL is versioned in parallel with the Namaste (XML->application->id->version) version. Each PDO_SQL
|
||||
// sub-container has several fields - one of which has the version identifier. When the deployment script
|
||||
// executes, the release versions are compared and, if they're an exact match, the SQL is submitted for execution.
|
||||
//
|
||||
// The PDO_SQL container consists of these sub-containers:
|
||||
//
|
||||
// PDO_SQL_VERSION --> this is a float value in the form of x.y as namaste only supports versions as a major
|
||||
// and minor release number. (Patch releases are minor release increments.)
|
||||
// PDO_TABLE --> string value containing the full table name.
|
||||
// PDO_SQL_FC --> the FC means "first commit" -- when the table is first created, it will execute the
|
||||
// SQL in this block, if it exists, and if the version number for the sub-container
|
||||
// exactly matched the version number in the configuration XML.
|
||||
// PDO_SQL_UPDATE --> When the sub-container PDO_SQL_VERSION value exactly matches the XML release value,
|
||||
// then the ALTER-TABLE sql in this update block will be executed.
|
||||
// STRING_DROP_CODE_IDX --> The boilerplate code for dropping the indexes of the table.
|
||||
// STRING_DROP_CODE_DEV --> For version 1.0 only, this points to code to drop the entire table.
|
||||
//
|
||||
// Again, containers themselves are indexed arrays under the PDO_SQL tag. Within the container, data is stored
|
||||
// as an associative array with the keys enumerated above.
|
||||
//
|
||||
//
|
||||
// DB OBJECTS:
|
||||
// -----------
|
||||
// DB objects are: views, procedures, functions and events.
|
||||
// All such objects assigned to a class are declared in this array under the appropriate header.
|
||||
// This is a safety-feature that prevents a one class (table) from invoking another class object.
|
||||
// The name of the object is stored as an indexed-array under the appropriate header.
|
||||
//
|
||||
// The format for these structures is basically the same. Each DBO is stored in an associative array with the
|
||||
// key defining the name of the object. Within each object, there are embedded associative arrays that have the
|
||||
// name of the object as the key and the object definition (text) and the value:
|
||||
//
|
||||
// objectType => [ objectName => [ objectContent ], ... ]
|
||||
//
|
||||
// Each created object should also have the directive to remove it's predecessor using a DROP statement.
|
||||
//
|
||||
// todo -- unset these objects post-instantiation so that schema is not revealed
|
||||
//
|
||||
// VIEWS:
|
||||
// ------
|
||||
// Every namaste table will have at least one view which limits the data fetched from the table. At a minimum,
|
||||
// the id_{ext} field is filtered from the resulting data set via the view. Other fields can be withheld as well
|
||||
// but that is something that is individually set-up for each table.
|
||||
//
|
||||
// The basic view has the following syntax for declaring it's name:
|
||||
// view_basic_{tableName_ext}
|
||||
// All views start with the word "view" so as to self-identify the object, followed by the view type which,
|
||||
// optimally, you should try to limit to a single, descriptive word.
|
||||
//
|
||||
// Following this label, which points to a sub-array containing three elements:
|
||||
// STRING_VIEW ----------> this is the SQL code that defines the view as a single string value
|
||||
// STRING_TYPE_LIST -----> null or an array of types that corresponds to variable markers ('?') in the sql
|
||||
// STRING_DESCRIPTION' --> a string that describes the purpose of the view.
|
||||
//
|
||||
// At a minimum, every class definition should contain at-least a basic view as all queries that don't specify
|
||||
// a named view or other DBO, will default to the the basic view in the FROM clause of the generated SQL.
|
||||
//
|
||||
// PROCEDURES:
|
||||
// -----------
|
||||
// For stored procedures, which are entirely optional, the array definition contains the following elements:
|
||||
// STRING_PROCEDURE -------> the SQL code that defined the stored procedure as a single string value
|
||||
// STRING_DROP_CODE -------> the sql code that drops the procedure (required for procedures!)
|
||||
// STRING_TYPE_LIST -------> an associative array of associative arrays -- in the top level, the key is the name
|
||||
// of the parameter that points to a sub-array that contains the parameter direction
|
||||
// as the key, and the parameter type as the value. There should be an entry for each
|
||||
// parameter to be passed to the stored procedure/function.
|
||||
//
|
||||
// ------------------------------------------------------
|
||||
// | NOTE: IN params must precede INOUT and OUT params! |
|
||||
// ------------------------------------------------------
|
||||
//
|
||||
// STRING_SP_EVENT_TYPE ---> Assign one of the DB_EVENT constants to this field to indicate the type of
|
||||
// query the stored-procedure will execute.
|
||||
// NOTE: there is not a defined PDO::PARAM constant for type float: use string.
|
||||
// STRING_DESCRIPTION -----> clear-text definition of the procedure's purpose
|
||||
//
|
||||
// Note that all of these containers are required; empty containers should contain a null placeholder.
|
||||
//
|
||||
// When a stored procedure contains a join of two or more tables/views, the first table listed is considered
|
||||
// to be the "owning" table and the procedure will be declared in the class template for that table, but it will
|
||||
// not be duplicated in other template classes referenced in the join.
|
||||
//
|
||||
public ?array $dbObjects = [
|
||||
PDO_SQL => [
|
||||
[
|
||||
PDO_VERSION => 1.0,
|
||||
PDO_TABLE => 'gaProductRegistrations_prg',
|
||||
PDO_SQL_FC => "
|
||||
--
|
||||
-- Table structure for table `gaProductRegistrations_prg`
|
||||
--
|
||||
|
||||
CREATE TABLE `gaProductRegistrations_prg` (
|
||||
`id_prg` int(10) UNSIGNED NOT NULL,
|
||||
`type_prg` char(16) NOT NULL,
|
||||
`iid_prg` char(64) NOT NULL,
|
||||
`eav_prg` char(16) DEFAULT NULL,
|
||||
`platform_prg` char(32) DEFAULT NULL,
|
||||
`browser_prg` char(32) DEFAULT NULL,
|
||||
`majorVersion_prg` int(11) DEFAULT NULL,
|
||||
`minorVersion_prg` int(11) DEFAULT NULL,
|
||||
`isMobile_prg` tinyint(3) UNSIGNED DEFAULT NULL,
|
||||
`isTablet_prg` tinyint(3) UNSIGNED DEFAULT NULL,
|
||||
`firstSeen_prg` datetime DEFAULT NULL,
|
||||
`lastSeen_prg` datetime DEFAULT NULL,
|
||||
`token_prg` char(36) NOT NULL,
|
||||
`eventGUID_prg` char(36) DEFAULT NULL,
|
||||
`createdDate_prg` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
`lastAccessedDate_prg` datetime DEFAULT NULL,
|
||||
`status_prg` varchar(25) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
",
|
||||
PDO_SQL_UPDATE => "
|
||||
--
|
||||
-- Indexes for table `gaProductRegistrations_prg`
|
||||
--
|
||||
ALTER TABLE `gaProductRegistrations_prg`
|
||||
ADD PRIMARY KEY (`id_prg`),
|
||||
ADD UNIQUE KEY `token_prg` (`token_prg`),
|
||||
ADD KEY `type_prg` (`type_prg`,`iid_prg`),
|
||||
ADD KEY `createdDate_prg` (`createdDate_prg`,`lastAccessedDate_prg`,`status_prg`),
|
||||
ADD KEY `iid_prg` (`iid_prg`,`eav_prg`),
|
||||
ADD KEY `eventGUID_prg` (`eventGUID_prg`);
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT for table `gaProductRegistrations_prg`
|
||||
--
|
||||
ALTER TABLE `gaProductRegistrations_prg`
|
||||
MODIFY `id_prg` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;
|
||||
",
|
||||
/*
|
||||
* example query return:
|
||||
* ---------------------
|
||||
* ALTER TABLE gaTest_tst DROP INDEX gaTest_tst_createdDate_tst_status_tst_index, DROP INDEX
|
||||
* gaTest_tst_lastAccessedDate_tst_index, DROP INDEX testInteger_tst, DROP INDEX
|
||||
* gaTest_tst_eventGuid_tst_index, DROP INDEX testDouble_tst, DROP INDEX testString_tst;
|
||||
*
|
||||
* NOTE:
|
||||
* -----
|
||||
* The sql comment code tag (--) will be removed during mysqlConfig's run time processing
|
||||
*/
|
||||
STRING_DROP_CODE_IDX => "--
|
||||
SELECT CONCAT('ALTER TABLE ', `Table`, ' DROP INDEX ', GROUP_CONCAT(`Index` SEPARATOR ', DROP INDEX '),';' )
|
||||
FROM (
|
||||
SELECT table_name AS `Table`, index_name AS `Index`
|
||||
FROM information_schema.statistics
|
||||
WHERE INDEX_NAME != 'PRIMARY'
|
||||
AND table_schema = 'XXXDROP_DB_NAMEXXX'
|
||||
AND table_name = 'XXXDROP_TABLE_NAMEXXX'
|
||||
GROUP BY `Table`, `Index`) AS tmp
|
||||
GROUP BY `Table`;
|
||||
",
|
||||
STRING_DROP_CODE_DEV => "DROP TABLE IF EXISTS gaProductRegistrations_prg;" // only executed if declared
|
||||
]
|
||||
],
|
||||
PDO_VIEWS => [
|
||||
'view_basic_gaProductRegistrations' => [
|
||||
STRING_VIEW =>
|
||||
"DROP VIEW IF EXISTS view_basic_gaProductRegistrations;
|
||||
CREATE VIEW view_basic_gaProductRegistrations_prg AS
|
||||
SELECT type_prg, iid_prg, eav_prg, platform_prg, browser_prg, majorVersion_prg, minorVersion_prg,
|
||||
isMobile_prg, isTablet_prg, firstSeen_prg, lastSeen_prg, eventGUID_prg, createdDate_prg,
|
||||
lastAccessedDate_prg, status_prg, token_prg
|
||||
FROM gaProductRegistrations_prg
|
||||
WHERE status_prg <> \"DELETE\";",
|
||||
STRING_TYPE_LIST => null,
|
||||
STRING_DESCRIPTION => 'basic query'
|
||||
],
|
||||
],
|
||||
PDO_PROCEDURES => [],
|
||||
PDO_FUNCTIONS => [],
|
||||
PDO_EVENTS => [],
|
||||
PDO_TRIGGERS => []
|
||||
];
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// MIGRATION DECLARATIONS
|
||||
// ----------------------
|
||||
// Data in this section is used to handle migrations -- when we're pulling from legacy tables into the Namaste
|
||||
// framework. See online doc for more info.
|
||||
//=================================================================================================================
|
||||
|
||||
/**
|
||||
* The migration map is an associative array that maps the Namaste fields (keys) to the corresponding
|
||||
* (remote) legacy fields in the source table to be migrated to Namaste.
|
||||
*
|
||||
* For example, if we were migrating a mysql table in the legacy production database to Namaste::mongo, then
|
||||
* the keys of the migration map would be the Namaste::mongo->fieldNames and the values would be the mysql
|
||||
* column names in the legacy table.
|
||||
*
|
||||
* If there is a value which cannot be mapped to a key, then set it to null.
|
||||
*
|
||||
* Fields that will be dropped in the migration are not listed as values or as keys.
|
||||
*
|
||||
* This map will only exist in the template object and will never be imported into the class widget.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationMap = [
|
||||
PDO_ID => null, // created on insert
|
||||
PRG_TYPE => 'type',
|
||||
PRG_IID => 'iid',
|
||||
PRG_EAV => 'eav',
|
||||
PRG_PLATFORM => 'platform',
|
||||
PRG_BROWSER => 'browser',
|
||||
PRG_MAJOR_VERSION => 'major_version',
|
||||
PRG_MINOR_VERSION => 'minor_version',
|
||||
PRG_IS_MOBILE => 'is_mobile',
|
||||
PRG_IS_TABLET => 'is_tablet',
|
||||
PRG_FIRST_SEEN => 'first_seen',
|
||||
PRG_LAST_SEEN => 'last_seen',
|
||||
DB_TOKEN => null, // created on insert
|
||||
DB_EVENT_GUID => null, // generated by broker event
|
||||
DB_CREATED => 'kinsert_date', // epoch time
|
||||
DB_STATUS => null, // record status
|
||||
DB_ACCESSED => 'kupdate_date' // epoch time
|
||||
];
|
||||
|
||||
/*
|
||||
* the migrationSortKey defines the SOURCE field by which the fetch query will be sorted. ALL sort fields are
|
||||
* in ASC order so all we need to list here is the name of the field -- which MUST BE IN THE SOURCE TABLE.
|
||||
*
|
||||
* Populating this field may require preliminary examination of the data - what we want is a field that has
|
||||
* zero NULL values.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?string $migrationSortKey = 'last_seen';
|
||||
|
||||
/*
|
||||
* The migrationStatusKey defines the status field/column in the source table -- if the user requires that
|
||||
* soft-deleted records not be migrated, then this field must be set. Otherwise, set the value to null.
|
||||
*
|
||||
* The format is in the form of a key-value paired array. The key specifies the name of the column and the value
|
||||
* specifies the "deleted" value that, if found, will cause that row from the SOURCE data to be omitted from the
|
||||
* DESTINATION table.
|
||||
*
|
||||
* e.g.: $migrationStatusKV = [ 'some_field' => 'deleted' ]
|
||||
*
|
||||
* Note that both the key and the value are case-sensitive!
|
||||
*
|
||||
* This is an optional field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationStatusKV = null;
|
||||
|
||||
// The $migrationSourceSchema defines the remote schema for the source table, and is set in the constructor
|
||||
public ?string $migrationSourceSchema;
|
||||
|
||||
// The source table in the remote repos (default defined in the XML) must be declared here, set in the constructor
|
||||
public ?string $migrationSourceTable;
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => true, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => true, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => true, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => true, // true to allow an ad-hoc query filter or if WH_REMOTE_SUPPORT is true
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [ OPERAND_NULL => [ OPERATOR_LT => [ null ] ] ],
|
||||
DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-23-18 mks CORE-852: original coding
|
||||
* 09-09-19 mks DB-111: initialization of migration members moved to constructor b/c IDE warnings.
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
$this->migrationSourceSchema = STRING_MYSQL; // or STRING_MONGO
|
||||
$this->migrationSourceTable = 'product_registrations';
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-23-18 mks CORE-852: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-23-18 mks CORE-852: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// empty by design
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
550
classes/templates/gatProductRegistrations.class.inc
Normal file
550
classes/templates/gatProductRegistrations.class.inc
Normal file
@@ -0,0 +1,550 @@
|
||||
<?php
|
||||
/**
|
||||
* gatProductRegistrations -- mongo template class
|
||||
*
|
||||
* This is the mongo template for givva.product_registrations, previously a mySQL-schema based table.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
* 01-13-20 mks DB-150: PHP7.4 class member type-casting
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
|
||||
class gatProductRegistrations
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version: not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_APPSERVER; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_PRODUCT_REG; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_PROD_REGS; // sets the collection (table) name
|
||||
public ?string $whTemplate = TEMPLATE_CLASS_WHC1_PROD_REG; // name of the warehouse template (not collection)
|
||||
public string $extension = COLLECTION_MONGO_PROD_REG_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set 2 true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = false; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_OBJECT, // sorting by the id is just like sorting by createdDate
|
||||
PRG_TYPE => DATA_TYPE_STRING,
|
||||
PRG_IID => DATA_TYPE_STRING,
|
||||
PRG_EAV => DATA_TYPE_STRING,
|
||||
PRG_PLATFORM => DATA_TYPE_STRING,
|
||||
PRG_BROWSER => DATA_TYPE_STRING,
|
||||
PRG_MAJOR_VERSION => DATA_TYPE_INTEGER,
|
||||
PRG_MINOR_VERSION => DATA_TYPE_INTEGER,
|
||||
PRG_IS_MOBILE => DATA_TYPE_INTEGER,
|
||||
PRG_IS_TABLET => DATA_TYPE_INTEGER,
|
||||
PRG_FIRST_SEEN => DATA_TYPE_STRING,
|
||||
PRG_LAST_SEEN => DATA_TYPE_STRING,
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (string) exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER // epoch time
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
PRG_IID, DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, MONGO_ID
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_CREATED, DB_TOKEN, DB_ACCESSED, DB_STATUS, PRG_TYPE, PRG_IID, PRG_EAV, DB_EVENT_GUID
|
||||
];
|
||||
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
PRG_EAV => 1,
|
||||
PRG_IID => 1,
|
||||
PRG_TYPE => 1,
|
||||
DB_CREATED => 1,
|
||||
DB_STATUS => 1,
|
||||
DB_EVENT_GUID => 1 // event guid should always be indexed
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
PRG_IID => 1,
|
||||
DB_TOKEN => 1 // MONGO_TOKEN should always appear
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
PRG_TYPE => CM_PRG_TYPE,
|
||||
PRG_IID => CM_PRG_IID,
|
||||
PRG_EAV => CM_PRG_EAV,
|
||||
PRG_PLATFORM => CM_PRG_PLATFORM,
|
||||
PRG_BROWSER => CM_PRG_BROWSER,
|
||||
PRG_MAJOR_VERSION => CM_PRG_MAJ_VER,
|
||||
PRG_MINOR_VERSION => CM_PRG_MIN_VER,
|
||||
PRG_IS_MOBILE => CM_PRG_IS_MOBILE,
|
||||
PRG_IS_TABLET => CM_PRG_IS_TABLET,
|
||||
PRG_FIRST_SEEN => CM_PRG_FIRST_SEEN,
|
||||
PRG_LAST_SEEN => CM_PRG_LAST_SEEN,
|
||||
DB_TOKEN => CM_TST_TOKEN,
|
||||
DB_STATUS => CM_TST_FIELD_TEST_STATUS,
|
||||
DB_EVENT_GUID => CM_TST_EVENT_GUID,
|
||||
DB_CREATED => CM_TST_FIELD_TEST_CDATE,
|
||||
DB_ACCESSED => CM_TST_FIELD_TEST_ADATE
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
* SubC fields do not need to be indexed.
|
||||
*
|
||||
*/
|
||||
public ?array $subC = null;
|
||||
|
||||
//=================================================================================================================
|
||||
// MIGRATION DECLARATIONS
|
||||
// ----------------------
|
||||
// Data in this section is used to handle migrations -- when we're pulling from legacy tables into the Namaste
|
||||
// framework. See online doc for more info.
|
||||
//=================================================================================================================
|
||||
|
||||
/**
|
||||
* The migration map is an associative array that maps the Namaste fields (keys) to the corresponding
|
||||
* (remote) legacy fields in the source table to be migrated to Namaste.
|
||||
*
|
||||
* For example, if we were migrating a mysql table in the legacy production database to Namaste::mongo, then
|
||||
* the keys of the migration map would be the Namaste::mongo->fieldNames and the values would be the mysql
|
||||
* column names in the legacy table.
|
||||
*
|
||||
* If there is a value which cannot be mapped to a key, then set it to null.
|
||||
*
|
||||
* Fields that will be dropped in the migration are not listed as values or as keys.
|
||||
*
|
||||
* This map will only exist in the template object and will never be imported into the class widget.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationMap = [
|
||||
MONGO_ID => null, // created on insert
|
||||
PRG_TYPE => 'type',
|
||||
PRG_IID => 'iid',
|
||||
PRG_EAV => 'eav',
|
||||
PRG_PLATFORM => 'platform',
|
||||
PRG_BROWSER => 'browser',
|
||||
PRG_MAJOR_VERSION => 'major_version',
|
||||
PRG_MINOR_VERSION => 'minor_version',
|
||||
PRG_IS_MOBILE => 'is_mobile',
|
||||
PRG_IS_TABLET => 'is_tablet',
|
||||
PRG_FIRST_SEEN => 'first_seen',
|
||||
PRG_LAST_SEEN => 'last_seen',
|
||||
DB_TOKEN => null, // created on insert
|
||||
DB_EVENT_GUID => null, // generated by broker event
|
||||
DB_CREATED => 'kinsert_date', // epoch time
|
||||
DB_STATUS => null, // record status
|
||||
DB_ACCESSED => 'kupdate_date' // epoch time
|
||||
];
|
||||
|
||||
/*
|
||||
* the migrationSortKey defines the SOURCE field by which the fetch query will be sorted. ALL sort fields are
|
||||
* in ASC order so all we need to list here is the name of the field -- which MUST BE IN THE SOURCE TABLE.
|
||||
*
|
||||
* Populating this field may require preliminary examination of the data - what we want is a field that has
|
||||
* zero NULL values.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?string $migrationSortKey = 'last_seen';
|
||||
|
||||
/*
|
||||
* The migrationStatusKey defines the status field/column in the source table -- if the user requires that
|
||||
* soft-deleted records not be migrated, then this field must be set. Otherwise, set the value to null.
|
||||
*
|
||||
* The format is in the form of a key-value paired array. The key specifies the name of the column and the value
|
||||
* specifies the "deleted" value that, if found, will cause that row from the SOURCE data to be omitted from the
|
||||
* DESTINATION table.
|
||||
*
|
||||
* e.g.: $migrationStatusKV = [ 'some_field' => 'deleted' ]
|
||||
*
|
||||
* Note that both the key and the value are case-sensitive!
|
||||
*
|
||||
* This is an optional field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationStatusKV = null;
|
||||
|
||||
// The $migrationSourceSchema defines the remote schema for the source table, and is set in the constructor
|
||||
public ?string $migrationSourceSchema;
|
||||
|
||||
// The source table in the remote repos (default defined in the XML) must be declared here, set in the constructor
|
||||
public ?string $migrationSourceTable;
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => true, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => true, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => true, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => true, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
WH_INDEXES => [DB_CREATED, DB_WH_CREATED],
|
||||
WH_TEMPLATE => '',
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [ OPERAND_NULL => [ OPERATOR_LT => [ null ] ] ],
|
||||
DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
* 09-09-19 mks DB-111: initialization of migration members moved to constructor b/c IDE warnings.
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
$this->migrationSourceSchema = STRING_MYSQL; // or STRING_MONGO
|
||||
$this->migrationSourceTable = 'product_registrations';
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
451
classes/templates/gatProductSessionUsers.class.inc
Normal file
451
classes/templates/gatProductSessionUsers.class.inc
Normal file
@@ -0,0 +1,451 @@
|
||||
<?php
|
||||
/**
|
||||
* gatProductSessionUsers -- mongo template class
|
||||
*
|
||||
* This is the mongo template for givva.product_session_users, previously a mySQL-schema based table.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
* 04-19-18 mks _INF-188: warehousing section added
|
||||
* 11-04-19 mks DB-136: fixed error where indexFields was missing a member element from singleIndex
|
||||
* 01-13-20 mks DB-150: PHP7.4 class member type-casting
|
||||
*
|
||||
*/
|
||||
class gatProductSessionUsers
|
||||
{
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_APPSERVER; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_PRODUCT_SES_USR; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_PSU; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_PSU_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = false; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
PSU_SID => DATA_TYPE_STRING,
|
||||
PSU_UID => DATA_TYPE_STRING,
|
||||
PSU_FIRST_SEEN => DATA_TYPE_STRING,
|
||||
PSU_LAST_SEEN => DATA_TYPE_STRING,
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (string) exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER // epoch time
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
PSU_SID, PSU_UID, DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, MONGO_ID
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_CREATED, DB_TOKEN, DB_ACCESSED, DB_STATUS, PSU_UID, PSU_SID, DB_EVENT_GUID
|
||||
];
|
||||
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = [ 'cIdx1UserSession' ];
|
||||
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_CREATED => 1,
|
||||
DB_STATUS => 1,
|
||||
DB_EVENT_GUID => 1 // event guid should always be indexed
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = [
|
||||
'cIdx1UserSession' => [ PSU_UID => 1, PSU_SID => 1]
|
||||
];
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1 // MONGO_TOKEN should always appear
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
PSU_SID => CM_PSU_SID,
|
||||
PSU_UID => CM_PSU_UID,
|
||||
PSU_FIRST_SEEN => CM_PSU_FIRST_SEEN,
|
||||
PSU_LAST_SEEN => CM_PSU_LAST_SEEN,
|
||||
DB_TOKEN => CM_TST_TOKEN,
|
||||
DB_STATUS => CM_TST_FIELD_TEST_STATUS,
|
||||
DB_EVENT_GUID => CM_TST_EVENT_GUID,
|
||||
DB_CREATED => CM_TST_FIELD_TEST_CDATE,
|
||||
DB_ACCESSED => CM_TST_FIELD_TEST_ADATE
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
* SubC fields do not need to be indexed.
|
||||
*
|
||||
*/
|
||||
public ?array $subC = null;
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [ OPERAND_NULL => [ OPERATOR_LT => [ null ] ] ],
|
||||
DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
456
classes/templates/gatProductSessions.class.inc
Normal file
456
classes/templates/gatProductSessions.class.inc
Normal file
@@ -0,0 +1,456 @@
|
||||
<?php
|
||||
/**
|
||||
* gatProductSessions -- mongo template class
|
||||
*
|
||||
* This is the mongo template for givva.product_sessions, previously a mySQL-schema based table.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
* 04-19-18 mks _INF-188: warehousing section added
|
||||
* 01-13-20 mks DB-150: PHP7.4 class member type-casting
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
|
||||
class gatProductSessions
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_APPSERVER; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_PRODUCT_SES; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_PROD_SESS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_PROD_SESS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = false; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
PSE_SID => DATA_TYPE_STRING,
|
||||
PSE_IID => DATA_TYPE_STRING,
|
||||
PSE_IP => DATA_TYPE_STRING,
|
||||
PSE_FIRST_SEEN => DATA_TYPE_STRING,
|
||||
PSE_LAST_SEEN => DATA_TYPE_STRING,
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (string) exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER // epoch time
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
PSE_IID, PSE_SID, DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, MONGO_ID
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_CREATED, DB_TOKEN, DB_ACCESSED, DB_STATUS, PSE_IP, PSE_SID, PSE_IID, DB_EVENT_GUID
|
||||
];
|
||||
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
PSE_IID => 1,
|
||||
PSE_SID => 1,
|
||||
PSE_IP => 1,
|
||||
DB_CREATED => 1,
|
||||
DB_STATUS => 1,
|
||||
DB_EVENT_GUID => 1 // event guid should always be indexed
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
PSE_SID => 1,
|
||||
DB_TOKEN => 1 // MONGO_TOKEN should always appear
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
PSE_SID => CM_PSE_SID,
|
||||
PSE_IID => CM_PSE_IID,
|
||||
PSE_IP => CM_PSE_IP,
|
||||
PSE_FIRST_SEEN => CM_PSE_FIRST_SEEN,
|
||||
PSE_LAST_SEEN => CM_PSE_LAST_SEEN,
|
||||
DB_TOKEN => CM_TST_TOKEN,
|
||||
DB_STATUS => CM_TST_FIELD_TEST_STATUS,
|
||||
DB_EVENT_GUID => CM_TST_EVENT_GUID,
|
||||
DB_CREATED => CM_TST_FIELD_TEST_CDATE,
|
||||
DB_ACCESSED => CM_TST_FIELD_TEST_ADATE
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
* SubC fields do not need to be indexed.
|
||||
*
|
||||
*/
|
||||
public ?array $subC = null;
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [ OPERAND_NULL => [ OPERATOR_LT => [ null ] ] ],
|
||||
DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
490
classes/templates/gatSMAXAPI.class.inc
Normal file
490
classes/templates/gatSMAXAPI.class.inc
Normal file
@@ -0,0 +1,490 @@
|
||||
<?php
|
||||
/**
|
||||
* gatSMAXAPI -- template class
|
||||
*
|
||||
* This template definition is for the Saarvus-Maximus (SMAX) API Partner tokens repository. A partner is required to
|
||||
* submit their token (GUID) value with every API request. This collection tracks those entries.
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 04-20-20 mks ECI-101: original coding
|
||||
* 06-01-20 mks ECI-108: support for auth tokens
|
||||
* 06-11-20 mks ECI-164: new field: TLTI
|
||||
*
|
||||
*/
|
||||
/** @noinspection PhpUnused */
|
||||
|
||||
class gatSMAXAPI
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_APPSERVER; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_SMAXAPI; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_SMAXAPI; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_SMAXAPI_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = false; // set to true to cache class data
|
||||
public bool $setDeletes = false; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_DESTRUCTIVE; // set to AUDIT_value constant (nondestructive = reads(yes))
|
||||
public bool $setJournaling = true; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique pkey exposed externally and is REQUIRED
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER, // epoch time
|
||||
SMAX_COMPANY_NAME => DATA_TYPE_STRING, // Name of company receiving API Key
|
||||
SMAX_COMPANY_CONTACT_INFO => DATA_TYPE_ARRAY, // array column, not a sub-collection
|
||||
SMAX_COMPANY_CONTACT_INFO_ADDRESS1 => DATA_TYPE_STRING,
|
||||
SMAX_COMPANY_CONTACT_INFO_ADDRESS2 => DATA_TYPE_STRING,
|
||||
SMAX_COMPANY_CONTACT_INFO_CITY => DATA_TYPE_STRING,
|
||||
SMAX_COMPANY_CONTACT_INFO_STATE => DATA_TYPE_STRING,
|
||||
SMAX_COMPANY_CONTACT_INFO_ZIP => DATA_TYPE_STRING,
|
||||
SMAX_COMPANY_PHONES => DATA_TYPE_OBJECT,
|
||||
SMAX_COMPANY_PHONES_VOICE => DATA_TYPE_STRING,
|
||||
SMAX_COMPANY_PHONES_FAX => DATA_TYPE_STRING,
|
||||
SMAX_COMPANY_CONTACTS => DATA_TYPE_ARRAY, // this is a sub-collection
|
||||
SMAX_COMPANY_CONTACTS_EMPLOYEE_NAME => DATA_TYPE_STRING,
|
||||
SMAX_COMPANY_CONTACTS_EMPLOYEE_EMAIL => DATA_TYPE_STRING,
|
||||
SMAX_COMPANY_CONTACTS_EMPLOYEE_PHONE_VOICE => DATA_TYPE_STRING,
|
||||
SMAX_COMPANY_CONTACTS_EMPLOYEE_PHONE_FAX => DATA_TYPE_STRING,
|
||||
SMAX_COMPANY_REGISTERED => DATA_TYPE_INTEGER,
|
||||
SMAX_COMPANY_LICENSE_DURATION => DATA_TYPE_INTEGER,
|
||||
SMAX_COMPANY_AUTHORIZED_BY => DATA_TYPE_STRING,
|
||||
SMAX_COMPANY_INTERNAL_NOTES => DATA_TYPE_STRING,
|
||||
SMAX_LICENSE_TYPE => DATA_TYPE_STRING,
|
||||
SMAX_TLTI => DATA_TYPE_STRING
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, MONGO_ID, SMAX_COMPANY_REGISTERED,
|
||||
SMAX_COMPANY_LICENSE_DURATION, SMAX_LICENSE_TYPE, SMAX_TLTI
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_CREATED, DB_STATUS, DB_TOKEN, SMAX_COMPANY_NAME,
|
||||
SMAX_COMPANY_AUTHORIZED_BY, SMAX_LICENSE_TYPE, SMAX_TLTI
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = [
|
||||
'cIdxCompanyNameStatus', 'cIdxCompanyJWTStatus', 'cIdxCompanyLicenseType'
|
||||
];
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_CREATED => -1,
|
||||
SMAX_COMPANY_NAME => 1,
|
||||
SMAX_COMPANY_AUTHORIZED_BY => 1
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = [
|
||||
'cIdxCompanyNameStatus' => [ SMAX_COMPANY_NAME => 1, DB_STATUS => 1],
|
||||
'cIdxCompanyLicenseType' => [ SMAX_LICENSE_TYPE => 1, DB_STATUS => 1]
|
||||
];
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Sparse indexes only add the row to the index if the column referenced satisfies the conditions specified
|
||||
// in the query condition (expr2).
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1, // MONGO_TOKEN should always appear
|
||||
SMAX_TLTI => 1 // Two-Letter Template Identifier must be unique
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null; // ttl indexes appear in $indexFields
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
DB_TOKEN => CM_TST_TOKEN,
|
||||
DB_STATUS => CM_TST_FIELD_TEST_STATUS,
|
||||
DB_EVENT_GUID => CM_TST_EVENT_GUID,
|
||||
DB_CREATED => CM_TRANSACTIONS_CREATED_AT,
|
||||
DB_ACCESSED => CM_TRANSACTIONS_UPDATED_AT,
|
||||
SMAX_COMPANY_NAME => CM_SMAX_COMPANY_NAME,
|
||||
SMAX_COMPANY_CONTACT_INFO => CM_SMAX_COMPANY_CONTACT_INFO,
|
||||
SMAX_COMPANY_CONTACT_INFO_ADDRESS1 => CM_SMAX_COMPANY_ADDR1,
|
||||
SMAX_COMPANY_CONTACT_INFO_ADDRESS2 => CM_SMAX_COMPANY_ADDR2,
|
||||
SMAX_COMPANY_CONTACT_INFO_CITY => CM_SMAX_COMPANY_CITY,
|
||||
SMAX_COMPANY_CONTACT_INFO_STATE => CM_SMAX_COMPANY_STATE,
|
||||
SMAX_COMPANY_CONTACT_INFO_ZIP => CM_SMAX_COMPANY_ZIP,
|
||||
SMAX_COMPANY_PHONES_VOICE => CM_SMAX_COMPANY_VOICE,
|
||||
SMAX_COMPANY_PHONES_FAX => CM_SMAX_COMPANY_FAX,
|
||||
SMAX_COMPANY_CONTACTS => CM_SMAX_CONTACTS,
|
||||
SMAX_COMPANY_CONTACTS_EMPLOYEE_NAME => CM_SMAX_CONTACT_NAME,
|
||||
SMAX_COMPANY_CONTACTS_EMPLOYEE_EMAIL => CM_SMAX_CONTACT_EMAIL,
|
||||
SMAX_COMPANY_CONTACTS_EMPLOYEE_PHONE_VOICE => CM_SMAX_CONTACT_VOICE,
|
||||
SMAX_COMPANY_CONTACTS_EMPLOYEE_PHONE_FAX => CM_SMAX_CONTACT_FAX,
|
||||
SMAX_COMPANY_AUTHORIZED_BY => CM_SMAX_AUTH_BY,
|
||||
SMAX_COMPANY_INTERNAL_NOTES => CM_SMAX_NOTES,
|
||||
SMAX_LICENSE_TYPE => CM_SMAX_ACCOUNT_TYPE,
|
||||
SMAX_TLTI => CM_SMAX_TLTI
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = [
|
||||
SMAX_COMPANY_CONTACTS => [
|
||||
SMAX_COMPANY_CONTACTS_EMPLOYEE_NAME,
|
||||
SMAX_COMPANY_CONTACTS_EMPLOYEE_EMAIL,
|
||||
SMAX_COMPANY_CONTACTS_EMPLOYEE_PHONE_VOICE,
|
||||
SMAX_COMPANY_CONTACTS_EMPLOYEE_PHONE_FAX
|
||||
]
|
||||
];
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [OPERAND_NULL => [OPERATOR_LT => [null]]],
|
||||
DB_STATUS => [OPERAND_NULL => [OPERATOR_EQ => [STATUS_ACTIVE]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-10-20 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-10-20 mks original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-10-20 mks original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// does nothing
|
||||
}
|
||||
|
||||
}
|
||||
634
classes/templates/gatSessions.class.inc
Normal file
634
classes/templates/gatSessions.class.inc
Normal file
@@ -0,0 +1,634 @@
|
||||
<?php /** @noinspection PhpUnused */
|
||||
|
||||
/**
|
||||
* Class gatSessions -- mongo class
|
||||
*
|
||||
* This class is used to store user sessions (assuming that the Users table is also a mongo collection). Sessions
|
||||
* are required for all communication with Namaste and must be linked to an active user, either external or internal,
|
||||
* account.
|
||||
*
|
||||
* Questions requiring resolution:
|
||||
* --------------------------------
|
||||
* -- what is the hard-expiration for a user session?
|
||||
* -- can a user have more than a single session open at a time?
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-03-20 mks DB-147: initial coding
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
|
||||
class gatSessions
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version; not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_TERCERO; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_SESSIONS; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_SESSIONS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_SESS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = false; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = false; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant (nondestructive = reads(yes))
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// non-standard template member variables
|
||||
public ?string $guid = null; // internal container for a guid value on instantiation
|
||||
public string $res = 'tSES: '; // resource identifier for logging
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_INTEGER,
|
||||
SESSION_EXPIRES => DATA_TYPE_DATETIME, // user-friendly time-stamp
|
||||
SESSION_CLOSED => DATA_TYPE_STRING, // timestamp for when the session was actually closed
|
||||
SESSION_DURATION => DATA_TYPE_INTEGER, // length of session in seconds
|
||||
SESSION_FK_USER => DATA_TYPE_STRING, // fk-link to users.token_usr
|
||||
SESSION_LEVEL => DATA_TYPE_INTEGER, // defines the session level (user, csr, etc.)
|
||||
SESSION_CUSTOM_FIELD => DATA_TYPE_STRING, // user-defined KEY
|
||||
SESSION_CUSTOM_VALUE => DATA_TYPE_STRING, // user-defined VALUE
|
||||
SESSION_CREATED_WITH => DATA_TYPE_OBJECT, // legacy-data container for json-looking stuff
|
||||
SESSION_ACTION => DATA_TYPE_STRING,
|
||||
SESSION_AUTH_PROVIDER => DATA_TYPE_STRING,
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER // epoch time
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_CREATED, DB_ACCESSED, SESSION_FK_USER, SESSION_LEVEL, SESSION_EXPIRES,
|
||||
SESSION_DURATION, MONGO_ID, DB_STATUS
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_TOKEN, SESSION_FK_USER, DB_STATUS, DB_EVENT_GUID
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = [
|
||||
'cIdxSession1'
|
||||
];
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_TOKEN => 1,
|
||||
DB_STATUS => 1,
|
||||
DB_EVENT_GUID => 1
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = [
|
||||
'cIdxSession1' => [ SESSION_FK_USER, DB_STATUS ]
|
||||
];
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Sparse indexes only add the row to the index if the column referenced satisfies the conditions specified
|
||||
// in the query condition (expr2).
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1, // MONGO_TOKEN should always appear
|
||||
DB_EVENT_GUID => 1
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
// cache maps are required for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
DB_TOKEN => CM_TOKEN,
|
||||
DB_CREATED => CM_DATE_CREATED,
|
||||
SESSION_CLOSED => CM_DATA_CLOSED,
|
||||
DB_ACCESSED => CM_DATE_ACCESSED,
|
||||
DB_STATUS => CM_STATUS,
|
||||
DB_EVENT_GUID => CM_EVENT_GUID,
|
||||
SESSION_EXPIRES => CM_SESSION_EXPIRES,
|
||||
SESSION_DURATION => CM_SESSION_DURATION,
|
||||
SESSION_LEVEL => CM_SESSION_LEVEL,
|
||||
SESSION_FK_USER => CM_SESSION_UID,
|
||||
SESSION_CUSTOM_FIELD => CM_SESSION_CUSTOM_KEY,
|
||||
SESSION_CUSTOM_VALUE => CM_SESSION_CUSTOM_VAL,
|
||||
SESSION_CREATED_WITH => CM_SESSION_CW,
|
||||
SESSION_ACTION => CM_SESSION_ACTION,
|
||||
SESSION_AUTH_PROVIDER => CM_SESSION_AP
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as the associative array: $exposedFields. Only those fields,
|
||||
* enumerated within this container, will be exposed to the client.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = [
|
||||
SESSION_ACTION => [ SESSION_ACTION, SESSION_CREATED_WITH ]
|
||||
];
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [OPERAND_NULL => [OPERATOR_LT => [null]]],
|
||||
DB_STATUS => [OPERAND_NULL => [OPERATOR_EQ => [STATUS_ACTIVE]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* Constructor in this template not only registers the shutdown method, but also allows us to generate a custom
|
||||
* GUID string during instantiation by use of the input parameters:
|
||||
*
|
||||
* $_getGUID - boolean, defaults to false but, if true, will generate a GUID value and store it in the class member
|
||||
* $_lc - boolean, defaults to false but, if true, will generate a GUID using lower-case alpha characters
|
||||
*
|
||||
* If we generate a GUID on instantiation, the GUID will be stored in the class member. This allows us to both
|
||||
* instantiate a session class object and a GUID value, (the most requested, post-instantiation, action), at the
|
||||
* same time. All the efficient.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param bool $_getGUID
|
||||
* @param bool $_lc
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-03-20 mks DB-147: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct(bool $_getGUID = false, bool $_lc = false)
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
if ($_getGUID) $this->guid = static::getGUID($_lc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* buildExpireSessionPayload() -- template function
|
||||
*
|
||||
* This is a "hidden function" for the session template class requiring the following input parameters:
|
||||
*
|
||||
* $_data -- the is the request payload as received by the tercero broker
|
||||
* $_errors -- call-by-reference container for error messaging
|
||||
*
|
||||
* The function will validate that $_data contains the $requiredArrayKeys, generating an error message if any
|
||||
* are not present in the _data array and returning a null value to the calling client if so.
|
||||
*
|
||||
* Depending on the value for STRING_TOK_TYPE stored in $_data, we'll build the query against DB_TOKEN or the
|
||||
* DB_EVENT_GUID.
|
||||
*
|
||||
* Then we just assemble the rest of the query and return the array to the calling client, presumably the sBroker.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $_data
|
||||
* @param array|null $_errors
|
||||
* @return array|null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-02-20 mks DB-168: original coding
|
||||
*
|
||||
*/
|
||||
public function buildExpireSessionPayload(array $_data, ?array &$_errors = null):?array
|
||||
{
|
||||
$requiredArrayKeys = [ STRING_GUID_KEY, STRING_TOK_TYPE ];
|
||||
$missingKey = false;
|
||||
try {
|
||||
$logger = new gacErrorLogger();
|
||||
// _data validation
|
||||
foreach ($requiredArrayKeys as $requiredKey) {
|
||||
if (!array_key_exists($requiredKey, $_data)) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$msg = ERROR_ARRAY_KEY_404 . $requiredKey;
|
||||
$_errors[] = $msg;
|
||||
$logger->data($hdr . $msg);
|
||||
$missingKey = true;
|
||||
}
|
||||
}
|
||||
if ($missingKey) return null;
|
||||
switch ($_data[STRING_TOK_TYPE]) {
|
||||
case STRING_TOK_TYPE_EVE :
|
||||
$searchDiscriminant = DB_EVENT_GUID;
|
||||
break;
|
||||
case STRING_TOK_TYPE_SES :
|
||||
case STRING_TOK_TYPE_TOK :
|
||||
$searchDiscriminant = DB_TOKEN;
|
||||
break;
|
||||
default :
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
$msg = ERROR_DATA_FIELD_NOT_MEMBER . $_data[STRING_TOK_TYPE];
|
||||
$_errors[] = $msg;
|
||||
$logger->data($hdr . $msg);
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
$query = [$searchDiscriminant => [ OPERAND_NULL => [ OPERATOR_EQ => [$_data[STRING_GUID_KEY]]]]];
|
||||
$update = [ DB_STATUS => STATUS_EXPIRED, SESSION_CLOSED => time() ];
|
||||
return [STRING_QUERY_DATA => $query, STRING_UPDATE_DATA => $update];
|
||||
} catch (Throwable | TypeError $t) {
|
||||
$hdr = sprintf(INFO_LOC, basename(__METHOD__), __LINE__);
|
||||
@handleExceptionMessaging($hdr, $t->getMessage(), $_errors, true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* buidlCloseSysEventPayload() -- public function
|
||||
*
|
||||
* This function requires a single input parameter:
|
||||
*
|
||||
* $_guid -- the session guid (foreign key value) in the system event record we're updating
|
||||
*
|
||||
* The method takes this information and build an update-record payload that will be returned to the adminIn
|
||||
* broker to close the system-event record that recorded the original session-expiry event.
|
||||
*
|
||||
* The function returns a string, which is the compress json query payload to be send immediately to the broker.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param string $_guid
|
||||
* @return string|null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 10-23-20 mks DB-168: original coding
|
||||
*
|
||||
*/
|
||||
public function buildCloseSysEventPayload(string $_guid):string
|
||||
{
|
||||
$payload = [
|
||||
SYSTEM_EVENT_STATUS => STATUS_CLOSED,
|
||||
DB_ACCESSED => time(),
|
||||
];
|
||||
$meta = [
|
||||
META_TEMPLATE => TEMPLATE_CLASS_SYS_EVENTS,
|
||||
META_CLIENT => CLIENT_SYSTEM,
|
||||
META_DO_CACHE => 0
|
||||
];
|
||||
$request = [
|
||||
BROKER_REQUEST => BROKER_REQUEST_UPDATE,
|
||||
BROKER_DATA => [
|
||||
STRING_QUERY_DATA => [ SYSTEM_EVENT_FK_SESSION_GUID => [ OPERAND_NULL => [OPERATOR_EQ => [$_guid]]]],
|
||||
STRING_UPDATE_DATA => $payload
|
||||
],
|
||||
BROKER_META_DATA => $meta
|
||||
];
|
||||
return gzcompress(json_encode($request));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* getGUID() -- public static template method
|
||||
*
|
||||
* This method calls the generic function method (guid()) which generates a random GUID (36-char format).
|
||||
*
|
||||
* The method has one input parameter:
|
||||
*
|
||||
* $_lc -- boolean: default set to false but, if true, converts the alpha chars in the guid string to lower-case.
|
||||
*
|
||||
* The method returns a string back to the calling client containing the 36-character GUID.
|
||||
*
|
||||
*
|
||||
* @param bool $_lc - defaults to false, submit true if your want the guid's alpha chars converted to lower-case
|
||||
* @return string
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-04-20 mks DB-147: original coding
|
||||
*
|
||||
*/
|
||||
public static function getGUID(bool $_lc = false):string
|
||||
{
|
||||
return (($_lc) ? strtolower(guid()) : guid());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-03-20 mks DB-147: original coding
|
||||
*
|
||||
* @version 1.0
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-03-20 mks DB-147: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// does nothing
|
||||
}
|
||||
}
|
||||
501
classes/templates/gatSystemData.class.inc
Normal file
501
classes/templates/gatSystemData.class.inc
Normal file
@@ -0,0 +1,501 @@
|
||||
<?php
|
||||
/**
|
||||
* gatSystemData -- mongo template class
|
||||
*
|
||||
* This is the mongo data template for the system data class. The system data class resides on the Admin service
|
||||
* and consists of a table with multiple rows. There's row identifier for "known" rows (states,status) and
|
||||
* "generic" columns for random key-value pairs.
|
||||
*
|
||||
* The systemData table is read and cached during IPL.
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 00-00-00 mks Original coding
|
||||
* 01-14-20 mks DB-150: PHP7.4 class member type-casting
|
||||
* 06-01-20 mks ECI-108: support for auth tokens
|
||||
*
|
||||
*/
|
||||
|
||||
class gatSystemData
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_ADMIN; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_SYS_DATA; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_SYS_DATA; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // name of the warehouse template (not collection)
|
||||
public string $extension = COLLECTION_MONGO_SYS_DATA_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = false; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_OBJECT, // sorting by the id is just like sorting by createdDate
|
||||
ROW_ID => DATA_TYPE_INTEGER, // simple, imposed, identifier for well-known rows
|
||||
DATA_KEY => DATA_TYPE_STRING, // label for key->value pair
|
||||
DATA_VALUE => DATA_TYPE_STRING, // value for key->value pair
|
||||
VALID_STATES => DATA_TYPE_ARRAY,
|
||||
VALID_STATUS => DATA_TYPE_ARRAY,
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (string) exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER // epoch time
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, MONGO_ID, ROW_ID
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, ROW_ID, DATA_KEY
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
public ?array $singleFields = [DATA_KEY => 1];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [ROW_ID => 1];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
VALID_STATUS => VALID_STATUS,
|
||||
VALID_STATES => VALID_STATES,
|
||||
ROW_ID => ROW_ID,
|
||||
DATA_KEY => DATA_KEY,
|
||||
DATA_VALUE => DATA_VALUE,
|
||||
DB_TOKEN => CM_TST_TOKEN,
|
||||
DB_STATUS => CM_TST_FIELD_TEST_STATUS,
|
||||
DB_EVENT_GUID => CM_TST_EVENT_GUID,
|
||||
DB_CREATED => CM_TST_FIELD_TEST_CDATE,
|
||||
DB_ACCESSED => CM_TST_FIELD_TEST_ADATE
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
* SubC fields do not need to be indexed.
|
||||
*
|
||||
*/
|
||||
public ?array $subC = null;
|
||||
|
||||
//=================================================================================================================
|
||||
// MIGRATION DECLARATIONS
|
||||
// ----------------------
|
||||
// Data in this section is used to handle migrations -- when we're pulling from legacy tables into the Namaste
|
||||
// framework. See online doc for more info.
|
||||
//=================================================================================================================
|
||||
|
||||
/**
|
||||
* The migration map is an associative array that maps the Namaste fields (keys) to the corresponding
|
||||
* (remote) legacy fields in the source table to be migrated to Namaste.
|
||||
*
|
||||
* For example, if we were migrating a mysql table in the legacy production database to Namaste::mongo, then
|
||||
* the keys of the migration map would be the Namaste::mongo->fieldNames and the values would be the mysql
|
||||
* column names in the legacy table.
|
||||
*
|
||||
* If there is a value which cannot be mapped to a key, then set it to null.
|
||||
*
|
||||
* Fields that will be dropped in the migration are not listed as values or as keys.
|
||||
*
|
||||
* This map will only exist in the template object and will never be imported into the class widget.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationMap = null;
|
||||
|
||||
/*
|
||||
* the migrationSortKey defines the SOURCE field by which the fetch query will be sorted. ALL sort fields are
|
||||
* in ASC order so all we need to list here is the name of the field -- which MUST BE IN THE SOURCE TABLE.
|
||||
*
|
||||
* Populating this field may require preliminary examination of the data - what we want is a field that has
|
||||
* zero NULL values.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?string $migrationSortKey = 'last_seen';
|
||||
|
||||
/*
|
||||
* The migrationStatusKey defines the status field/column in the source table -- if the user requires that
|
||||
* soft-deleted records not be migrated, then this field must be set. Otherwise, set the value to null.
|
||||
*
|
||||
* The format is in the form of a key-value paired array. The key specifies the name of the column and the value
|
||||
* specifies the "deleted" value that, if found, will cause that row from the SOURCE data to be omitted from the
|
||||
* DESTINATION table.
|
||||
*
|
||||
* e.g.: $migrationStatusKV = [ 'some_field' => 'deleted' ]
|
||||
*
|
||||
* Note that both the key and the value are case-sensitive!
|
||||
*
|
||||
* This is an optional field.
|
||||
*
|
||||
*/
|
||||
public ?string $migrationStatusKV = null;
|
||||
|
||||
// The $migrationSourceSchema defines the remote schema for the source table
|
||||
public ?string $migrationSourceSchema = ''; // or STRING_MONGO
|
||||
|
||||
// The source table in the remote repos (default defined in the XML) must be declared here
|
||||
public ?string $migrationSourceTable = '';
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
// todo -- add an "enabled" option to this block
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
WH_INDEXES => null,
|
||||
WH_TEMPLATE => '',
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => null
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 12-20-17 mks CORE-681: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
}
|
||||
486
classes/templates/gatSystemEvents.class.inc
Normal file
486
classes/templates/gatSystemEvents.class.inc
Normal file
@@ -0,0 +1,486 @@
|
||||
<?php
|
||||
/**
|
||||
* Class Template: gatSystemEvents
|
||||
* -------------------------------
|
||||
* This template defines the storage (mongo) for system-events.
|
||||
*
|
||||
* System events record data about routine and exception events that occur during normal processing/execution of
|
||||
* the Namaste framework. As such, it is strictly an administrative table and accessible via the admin system only.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-16-17 mks CORE-500: original programming
|
||||
* 04-19-18 mks _INF-188: warehousing section added
|
||||
* 11-04-19 mks DB-136: added DB_STATUS field to $indexFields, removed duplicate key from $fields
|
||||
* 01-14-20 mks DB-150: PHP7.4 class member type-casting
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
* 08-14-20 mks DB-168: added event status which is binary: success | fail
|
||||
*
|
||||
*/
|
||||
|
||||
class gatSystemEvents
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1;
|
||||
public string $service = CONFIG_DATABASE_SERVICE_ADMIN; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_SYS_EVENTS; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_SYS_EVENTS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_SYS_EVENTS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = false; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = false; // set to true to enable collection query timers
|
||||
public string $setPKey = SYSTEM_EVENT_FK_SESSION_GUID; // sets the primary key for the collection
|
||||
public bool $setTokens = false; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = true; // set to false if the class contains methods
|
||||
public int $cacheTimer = 0; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// all column names are defined as key->value pairs with the value being type specified by the given constant
|
||||
// all key names should also be declared constants.
|
||||
// note that key names do NOT have their extensions appended!
|
||||
|
||||
public array $fields = [
|
||||
// generic mongo constants
|
||||
MONGO_ID => DATA_TYPE_INTEGER,
|
||||
DB_STATUS => DATA_TYPE_STRING, // status of this record
|
||||
DB_CREATED => DATA_TYPE_INTEGER,
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING,
|
||||
// fields specific to systemEvents collection
|
||||
SYSTEM_EVENT_NAME => DATA_TYPE_STRING, // name of the event (pre-defined constant)
|
||||
SYSTEM_EVENT_STATUS => DATA_TYPE_STRING, // status of the event, not this record
|
||||
SYSTEM_EVENT_TYPE => DATA_TYPE_STRING, // event type (BROKER, TIMER, FATAL, etc.)
|
||||
SYSTEM_EVENT_CLASS => DATA_TYPE_STRING, // which class, if any, generated the event
|
||||
SYSTEM_EVENT_START => DATA_TYPE_INTEGER, // event starting value (memory)
|
||||
SYSTEM_EVENT_END => DATA_TYPE_INTEGER, // event ending value (memory)
|
||||
SYSTEM_EVENT_PEAK => DATA_TYPE_INTEGER, // event peak value (memory)
|
||||
SYSTEM_EVENT_TIMER => DATA_TYPE_DOUBLE, // Spot-timer for the event, absolute/real time
|
||||
SYSTEM_EVENT_AT_RESULTS => DATA_TYPE_ARRAY, // container for results of the AT(1) command
|
||||
SYSTEM_EVENT_DURATION => DATA_TYPE_INTEGER, // length of time for the event implying expiry
|
||||
SYSTEM_EVENT_BROKER_EVENT => DATA_TYPE_STRING, // the name of the broker event
|
||||
SYSTEM_EVENT_OGUID => DATA_TYPE_STRING, // the original guid (for cross-queue events)
|
||||
SYSTEM_EVENT_FK_SESSION_GUID => DATA_TYPE_STRING, // if we have a session GUID, store it here
|
||||
SYSTEM_EVENT_FK_USER_GUID => DATA_TYPE_STRING, // if we have a user GUID, store it here
|
||||
SYSTEM_EVENT_BROKER_GUID => DATA_TYPE_STRING, // broker (child) identifying guid
|
||||
SYSTEM_EVENT_COUNT => DATA_TYPE_INTEGER, // this event is event number...
|
||||
SYSTEM_EVENT_COUNT_TOTAL => DATA_TYPE_INTEGER, // ... out of this many events
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => DATA_TYPE_STRING, // broker (parent) identifying guid
|
||||
SYSTEM_EVENT_NUM_EVENTS => DATA_TYPE_INTEGER, // number of discrete sub-events (child broker)
|
||||
SYSTEM_EVENT_CODE_LOC => DATA_TYPE_STRING, // identified the code-location launching the event
|
||||
SYSTEM_EVENT_KEY => DATA_TYPE_STRING, // (optional) free-form key
|
||||
SYSTEM_EVENT_VAL => DATA_TYPE_INTEGER, // (optional) free-form value matched to key
|
||||
SYSTEM_EVENT_ERROR_STACK => DATA_TYPE_ARRAY, // (optional) the error-stack generated
|
||||
SYSTEM_EVENT_META_DATA => DATA_TYPE_ARRAY, // (optional) the meta-data received for the event
|
||||
SYSTEM_EVENT_NOTES => DATA_TYPE_STRING // (optional) free-form text
|
||||
|
||||
/*
|
||||
* other candidate fields for later expansion include, but are not limited to:
|
||||
*
|
||||
* -- mail GUID did we generate an outbound email?
|
||||
* -- AT_OUT output from AT(1) daemon on timer events
|
||||
* -- Severity? classify events by their assigned severity
|
||||
* -- responded if an event required intervention, when was it responded to?
|
||||
* -- respondedBy if an event required intervention, who was assigned to the event?
|
||||
* -- closed if an event required intervention, when was it closed?
|
||||
* -- resolution if an event required intervention, what was the resolution?
|
||||
*/
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID,
|
||||
DB_CREATED,
|
||||
DB_EVENT_GUID,
|
||||
SYSTEM_EVENT_BROKER_EVENT,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID,
|
||||
SYSTEM_EVENT_OGUID,
|
||||
SYSTEM_EVENT_FK_SESSION_GUID,
|
||||
SYSTEM_EVENT_BROKER_GUID,
|
||||
SYSTEM_EVENT_TYPE,
|
||||
SYSTEM_EVENT_NAME,
|
||||
SYSTEM_EVENT_STATUS,
|
||||
SYSTEM_EVENT_CLASS,
|
||||
DB_STATUS
|
||||
];
|
||||
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = [
|
||||
'cIdx1SEV',
|
||||
'cIdx2GUID',
|
||||
'cIdx2TYPE',
|
||||
'cIdx1SESS'
|
||||
];
|
||||
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_EVENT_GUID => 1,
|
||||
DB_CREATED => -1,
|
||||
SYSTEM_EVENT_BROKER_EVENT => 1,
|
||||
SYSTEM_EVENT_BROKER_GUID => 1,
|
||||
SYSTEM_EVENT_STATUS => 1,
|
||||
SYSTEM_EVENT_BROKER_ROOT_GUID => 1,
|
||||
SYSTEM_EVENT_TYPE => 1
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = [
|
||||
'cIdx1SEV' => [SYSTEM_EVENT_NAME => 1, SYSTEM_EVENT_CLASS => 1 ],
|
||||
'cIdx2GUID' => [ SYSTEM_EVENT_OGUID => 1, SYSTEM_EVENT_BROKER_GUID => 1 ],
|
||||
'cIdx2TYPE' => [ SYSTEM_EVENT_TYPE => 1, SYSTEM_EVENT_STATUS => 1],
|
||||
'cIdx1SESS' => [ SYSTEM_EVENT_FK_SESSION_GUID => 1, DB_STATUS => 1]
|
||||
];
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = null; // mongo TOKEN does not appear b/c system table
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null; // ttl indexes appear in $indexFields
|
||||
|
||||
// cache maps are required for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = null;
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = null;
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [ OPERAND_NULL => [ OPERATOR_LT => [ null ] ] ],
|
||||
DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-16-17 mks CORE-500: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-16-17 mks CORE-500: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-16-17 mks CORE-500: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// does nothing
|
||||
}
|
||||
}
|
||||
545
classes/templates/gatTestMongo.class.inc
Normal file
545
classes/templates/gatTestMongo.class.inc
Normal file
@@ -0,0 +1,545 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* gatTestMongo() -- mongo test class
|
||||
*
|
||||
* This class is used for testing mongo operations. It has it's own collection in the database and is used in testing
|
||||
* during development and in unit-testing.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-10-17 mks original coding
|
||||
* 08-04-17 mks added version control, partialIndexes
|
||||
* 09-12-17 mks CORE-558: protected fields
|
||||
* 04-19-18 mks _INF-188: warehousing section added
|
||||
* 01-14-20 mks DB-150: PHP7.4 class member type-casting
|
||||
* 06-01-20 mks ECI-120: support for auth token
|
||||
*
|
||||
*/
|
||||
class gatTestMongo
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_APPSERVER; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_TEST_MONGO; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_TEST; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_TEST_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = false; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NONDESTRUCTIVE; // set to AUDIT_value constant (nondestructive = reads(yes))
|
||||
public bool $setJournaling = true; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = false; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
TEST_FIELD_TEST_STRING => DATA_TYPE_STRING,
|
||||
TEST_FIELD_TEST_DOUBLE => DATA_TYPE_DOUBLE,
|
||||
TEST_FIELD_TEST_INT => DATA_TYPE_INTEGER,
|
||||
TEST_FIELD_TEST_NIF => DATA_TYPE_INTEGER, // used in unit testing for testing non-indexed queries
|
||||
TEST_FIELD_TEST_BOOL => DATA_TYPE_BOOL,
|
||||
TEST_FIELD_TEST_OBJECT => DATA_TYPE_OBJECT,
|
||||
TEST_FIELD_TEST_ARRAY => DATA_TYPE_ARRAY, // array of data (flat)
|
||||
TEST_FIELD_TEST_SUBC => DATA_TYPE_ARRAY, // subCollection (array of arrays which may contain arrays)
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (string) exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER // epoch time
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, MONGO_ID
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_CREATED, TEST_FIELD_TEST_INT, DB_TOKEN, TEST_FIELD_TEST_BOOL, DB_EVENT_GUID,
|
||||
TEST_FIELD_TEST_DOUBLE, DB_ACCESSED, TEST_FIELD_TEST_STRING, DB_STATUS, TEST_FIELD_TEST_OBJECT
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = [
|
||||
'cIdx1Test',
|
||||
'mIdx1Test',
|
||||
];
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
TEST_FIELD_TEST_BOOL => 1,
|
||||
TEST_FIELD_TEST_STRING => 1,
|
||||
DB_CREATED => -1,
|
||||
DB_STATUS => -1,
|
||||
DB_EVENT_GUID => 1 // event guid should always be indexed
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = [
|
||||
'cIdx1Test' => [TEST_FIELD_TEST_INT => 1, TEST_FIELD_TEST_DOUBLE => -1 ]
|
||||
];
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = [ 'mIdx1Test' => [TEST_FIELD_TEST_ARRAY. DOT . TEST_FIELD_TEST_INT => 1]];
|
||||
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Sparse indexes only add the row to the index if the column referenced satisfies the conditions specified
|
||||
// in the query condition (expr2).
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = [
|
||||
// this is a really bad example, but an example nonetheless, of a partial index
|
||||
[[ TEST_FIELD_TEST_OBJECT => 1], [ MONGO_STRING_PARTIAL_FE => [ DB_CREATED => [ MONGO_EXISTS => false ]]]],
|
||||
[[ TEST_FIELD_TEST_OBJECT => 1], [ MONGO_STRING_PARTIAL_FE => [ DB_CREATED => [ MONGO_EXISTS => true ]]]]
|
||||
];
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1 // MONGO_TOKEN should always appear
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = [DB_CREATED => 86400]; // ttl indexes appear in $indexFields
|
||||
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
TEST_FIELD_TEST_STRING => CM_TST_FIELD_TEST_STRING,
|
||||
TEST_FIELD_TEST_DOUBLE => CM_TST_FIELD_TEST_DOUBLE,
|
||||
TEST_FIELD_TEST_INT => CM_TST_FIELD_TEST_INT,
|
||||
TEST_FIELD_TEST_NIF => CM_TST_FIELD_TEST_NIF,
|
||||
TEST_FIELD_TEST_BOOL => CM_TST_FIELD_TEST_BOOL,
|
||||
TEST_FIELD_TEST_OBJECT => CM_TST_FIELD_TEST_OBJ,
|
||||
TEST_FIELD_TEST_ARRAY => CM_TST_FIELD_TEST_ARY,
|
||||
TEST_FIELD_TEST_SUBC => CM_TST_FIELD_TEST_SUBC,
|
||||
DB_TOKEN => CM_TST_TOKEN,
|
||||
DB_STATUS => CM_TST_FIELD_TEST_STATUS,
|
||||
DB_EVENT_GUID => CM_TST_EVENT_GUID,
|
||||
DB_CREATED => CM_TST_FIELD_TEST_CDATE,
|
||||
DB_ACCESSED => CM_TST_FIELD_TEST_ADATE
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = [ TEST_FIELD_TEST_STRING ];
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = [
|
||||
TEST_FIELD_TEST_SUBC => [
|
||||
TEST_FIELD_TEST_INT,
|
||||
TEST_FIELD_TEST_DOUBLE,
|
||||
TEST_FIELD_TEST_STRING,
|
||||
TEST_FIELD_TEST_BOOL,
|
||||
DB_TOKEN
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [ OPERAND_NULL => [ OPERATOR_LT => [ null ] ] ],
|
||||
DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-10-17 mks CORE-463: code complete (refactor from ddb to mdb)
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = '79344859-5403-1556-7663-4E34D6B4CBE4'; // SMAX-API record token
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* buildTestData() -- public static method
|
||||
*
|
||||
* this method is used to build an array structure of random data. There is only input parameter to the method
|
||||
* specifies the number of records to return to the calling client.
|
||||
*
|
||||
* The input parameter specifies how many records (indexes in the array) should be returned to the calling client
|
||||
* and should be a reasonable integer between one and one-hundred (1 - 100). If the passed-value for the number
|
||||
* of records is outside of this range, on either side, then the passed-value will be replaced with the range
|
||||
* limit for the appropriate "side".
|
||||
*
|
||||
* We then spin through a loop which populates an indexed array with the elements, from the test class,
|
||||
* with the appropriate extension as the sub-array key value.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param int $_records
|
||||
* @return null|array
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-10-17 mks original coding
|
||||
* 07-12-17 mks added object field to test data generation: a copy of the current record's data
|
||||
* 07-20-17 mks moved to gatTestMongo class where it belongs (testing selfDestruct feature in templates)
|
||||
* 04-15-19 mks DB-116: header re-formatted for PHP7 (type casting enforced)
|
||||
*
|
||||
*/
|
||||
public static function buildTestData(int $_records = 0): ?array
|
||||
{
|
||||
if ($_records < 1) $_records = 1;
|
||||
if ($_records > 1000) $_records = 1000;
|
||||
$retData = null;
|
||||
mt_srand();
|
||||
for ($index = 0; $index < $_records; $index++) {
|
||||
$sentenceCount = mt_rand(1, 20);
|
||||
$retData[$index][CM_TST_FIELD_TEST_INT] = $sentenceCount;
|
||||
$retData[$index][CM_TST_FIELD_TEST_NIF] = 1;
|
||||
$retData[$index][CM_TST_FIELD_TEST_DOUBLE] = floatval((1 / mt_rand(1, 10000)) * 100);
|
||||
$retData[$index][CM_TST_FIELD_TEST_BOOL] = (mt_rand(0, 1) == 1) ? true : false;
|
||||
$retData[$index][CM_TST_FIELD_TEST_STRING] = lorumIpsum($sentenceCount, 0);
|
||||
$retData[$index][CM_TST_FIELD_TEST_ARY] = [[
|
||||
CM_TST_FIELD_TEST_INT => rand(0,100),
|
||||
CM_TST_FIELD_TEST_STRING => STRING_DATA
|
||||
], [
|
||||
CM_TST_FIELD_TEST_INT => rand(100,200),
|
||||
CM_TST_FIELD_TEST_STRING => INFO_INTERNAL_REQUEST
|
||||
]];
|
||||
$retData[$index][CM_TST_FIELD_TEST_OBJ] = (object) [
|
||||
CM_TST_FIELD_TEST_INT => rand(0, 100),
|
||||
CM_TST_FIELD_TEST_STRING => STRING_DATA
|
||||
];
|
||||
$retData[$index][CM_TST_FIELD_TEST_SUBC][] = [
|
||||
CM_TST_FIELD_TEST_INT => $sentenceCount,
|
||||
CM_TST_FIELD_TEST_DOUBLE => $retData[$index][CM_TST_FIELD_TEST_DOUBLE],
|
||||
CM_TST_FIELD_TEST_BOOL => $retData[$index][CM_TST_FIELD_TEST_BOOL],
|
||||
CM_TST_FIELD_TEST_STRING => $retData[$index][CM_TST_FIELD_TEST_STRING]
|
||||
];
|
||||
}
|
||||
return ($retData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-10-17 mks CORE-463: code complete (refactor from ddb to mdb)
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 07-10-17 mks CORE-463: code complete (refactor from ddb to mdb)
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
701
classes/templates/gatTestPDO.class.inc
Normal file
701
classes/templates/gatTestPDO.class.inc
Normal file
@@ -0,0 +1,701 @@
|
||||
<?php
|
||||
/**
|
||||
* Class gatTestPDO -- PDO Test Class
|
||||
*
|
||||
* This class is a test class for PDO operations. It is used for stub and unit-testing, references it's own
|
||||
* database table, and is for development/QA use only.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-13-17 mks CORE-562: original coding
|
||||
* 04-19-18 mks _INF-188: warehousing section added
|
||||
* 06-13-18 mks CORE-1044: making a consistent, sample, PDO template
|
||||
* 01-18-19 mks DB-105: updated for audit/journaling unit testing
|
||||
* 02-05-19 mks DB-107: created audit_view for cross-broker queries by the audit service
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
class gatTestPDO
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_APPSERVER; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_PDO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_TEST_PDO; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_PDO_TEST; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_PDO_TEST_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = false; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NONDESTRUCTIVE; // set to AUDIT_value constant
|
||||
public bool $setJournaling = true; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = false; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
//
|
||||
// Note that for PDO-type tables, the data type is more ... homogeneous... e.g.: data types define the data
|
||||
// type only. It does not define the actual column type in-use. For example, there is no distinction made
|
||||
// between a tinyInt, Int, or BigInt. As far as the framework is concerned, they're all just integers.
|
||||
//
|
||||
public array $fields = [
|
||||
PDO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
TEST_FIELD_TEST_STRING => DATA_TYPE_STRING,
|
||||
TEST_FIELD_TEST_DOUBLE => DATA_TYPE_DOUBLE,
|
||||
TEST_FIELD_TEST_INT => DATA_TYPE_INTEGER,
|
||||
TEST_FIELD_TEST_BOOL => DATA_TYPE_INTEGER, // BOOLs in PDO are really tinyInt(1)
|
||||
TEST_FIELD_TEST_NIF => DATA_TYPE_INTEGER, // used in unit-testing -- never index this field
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (string) exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_STRING, // dateTime type
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_STRING // dateTime type
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, PDO_ID
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public array $indexFields = [
|
||||
PDO_ID, // implicitly indexed as pkey when table is created
|
||||
DB_CREATED, DB_STATUS, // compound index
|
||||
DB_TOKEN, // unique index
|
||||
TEST_FIELD_TEST_STRING, // for unit-testing
|
||||
TEST_FIELD_TEST_INT, DB_EVENT_GUID, // single field indexes...
|
||||
DB_ACCESSED, TEST_FIELD_TEST_DOUBLE
|
||||
];
|
||||
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = [ 'cIdx1ITest' ];
|
||||
|
||||
// the primary key index is declared in the class properties section as $setPKey
|
||||
|
||||
// unique indexes are to be used a values stored in these columns have to be unique to the table. Note that
|
||||
// null values are permissible in unique-index columns.
|
||||
public ?array $uniqueIndexes = [ DB_TOKEN ];
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index (index, multi)
|
||||
// the format for the single-field index declaration is a simple indexed array.
|
||||
public ?array $singleFields = [
|
||||
TEST_FIELD_TEST_INT, DB_ACCESSED, DB_EVENT_GUID, TEST_FIELD_TEST_DOUBLE, TEST_FIELD_TEST_STRING
|
||||
];
|
||||
|
||||
// multi-column (or compound) indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME1, FIELD_NAME2, ..., FIELD_NAMEn ]]
|
||||
// where INDEX-NAME is a unique string
|
||||
//
|
||||
// PDO compound-indexes are left-most indexes - if it cannot use the entire index, the db must be able to use
|
||||
// one, or more, of the left-most fields in the index.
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = [
|
||||
'cIdx1Test' => [ DB_CREATED, DB_STATUS ]
|
||||
];
|
||||
|
||||
|
||||
// NOTE: foreign-key indexes are not explicitly enumerated in a template -- that relationship is defined in the
|
||||
// schema for the table. Foreign-key indexes appear implicitly in the indexing declarations above.
|
||||
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
TEST_FIELD_TEST_STRING => CM_TST_FIELD_TEST_STRING,
|
||||
TEST_FIELD_TEST_DOUBLE => CM_TST_FIELD_TEST_DOUBLE,
|
||||
TEST_FIELD_TEST_INT => CM_TST_FIELD_TEST_INT,
|
||||
TEST_FIELD_TEST_BOOL => CM_TST_FIELD_TEST_BOOL,
|
||||
TEST_FIELD_TEST_NIF => CM_TST_FIELD_TEST_NIF,
|
||||
DB_TOKEN => CM_TST_TOKEN,
|
||||
DB_STATUS => CM_TST_FIELD_TEST_STATUS,
|
||||
DB_EVENT_GUID => CM_TST_EVENT_GUID,
|
||||
DB_CREATED => CM_TST_FIELD_TEST_CDATE,
|
||||
DB_ACCESSED => CM_TST_FIELD_TEST_ADATE
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
// in PDO-land, binary fields are your basic data blobs. All binary fields require special handling and so
|
||||
// need to be enumerated here as an indexed array.
|
||||
public ?array $binFields = null;
|
||||
|
||||
// DB SQL:
|
||||
// -------
|
||||
// PDO SQL is stored in the template and is keyed by the current namaste version (defined in the XML file) during
|
||||
// execution of the deployment script. Each version denotes a container of SQL commands that will be executed
|
||||
// for the targeted version.
|
||||
//
|
||||
// SQL is versioned in parallel with the Namaste (XML->application->id->version) version. Each PDO_SQL
|
||||
// sub-container has several fields - one of which has the version identifier. When the deployment script
|
||||
// executes, the release versions are compared and, if they're an exact match, the SQL is submitted for execution.
|
||||
//
|
||||
// The PDO_SQL container consists of these sub-containers:
|
||||
//
|
||||
// PDO_SQL_VERSION --> this is a float value in the form of x.y as namaste only supports versions as a major
|
||||
// and minor release number. (Patch releases are minor release increments.)
|
||||
// PDO_TABLE --> string value containing the full table name.
|
||||
// PDO_SQL_FC --> the FC means "first commit" -- when the table is first created, it will execute the
|
||||
// SQL in this block, if it exists, and if the version number for the sub-container
|
||||
// exactly matched the version number in the configuration XML.
|
||||
// PDO_SQL_UPDATE --> When the sub-container PDO_SQL_VERSION value exactly matches the XML release value,
|
||||
// then the ALTER-TABLE sql in this update block will be executed.
|
||||
// STRING_DROP_CODE_IDX --> The boilerplate code for dropping the indexes of the table.
|
||||
// STRING_DROP_CODE_DEV --> For version 1.0 only, this points to code to drop the entire table.
|
||||
//
|
||||
// Again, containers themselves are indexed arrays under the PDO_SQL tag. Within the container, data is stored
|
||||
// as an associative array with the keys enumerated above.
|
||||
//
|
||||
//
|
||||
// DB OBJECTS:
|
||||
// -----------
|
||||
// DB objects are: views, procedures, functions and events.
|
||||
// All such objects assigned to a class are declared in this array under the appropriate header.
|
||||
// This is a safety-feature that prevents a one class (table) from invoking another class object.
|
||||
// The name of the object is stored as an indexed-array under the appropriate header.
|
||||
//
|
||||
// The format for these structures is basically the same. Each DBO is stored in an associative array with the
|
||||
// key defining the name of the object. Within each object, there are embedded associative arrays that have the
|
||||
// name of the object as the key and the object definition (text) and the value:
|
||||
//
|
||||
// objectType => [ objectName => [ objectContent ], ... ]
|
||||
//
|
||||
// Each created object should also have the directive to remove it's predecessor using a DROP statement.
|
||||
//
|
||||
// todo -- unset these objects post-instantiation so that schema is not revealed
|
||||
//
|
||||
// VIEWS:
|
||||
// ------
|
||||
// Every namaste table will have at least one view which limits the data fetched from the table. At a minimum,
|
||||
// the id_{ext} field is filtered from the resulting data set via the view. Other fields can be withheld as well
|
||||
// but that is something that is individually set-up for each table.
|
||||
//
|
||||
// The basic view has the following syntax for declaring it's name:
|
||||
// view_basic_{tableName_ext}
|
||||
// All views start with the word "view" so as to self-identify the object, followed by the view type which,
|
||||
// optimally, you should try to limit to a single, descriptive word.
|
||||
//
|
||||
// Following this label, which points to a sub-array containing three elements:
|
||||
// STRING_VIEW ----------> this is the SQL code that defines the view as a single string value
|
||||
// STRING_TYPE_LIST -----> null or an array of types that corresponds to variable markers ('?') in the sql
|
||||
// STRING_DESCRIPTION' --> a string that describes the purpose of the view.
|
||||
//
|
||||
// At a minimum, every class definition should contain at-least a basic view as all queries that don't specify
|
||||
// a named view or other DBO, will default to the the basic view in the FROM clause of the generated SQL.
|
||||
//
|
||||
// PROCEDURES:
|
||||
// -----------
|
||||
// For stored procedures, which are entirely optional, the array definition contains the following elements:
|
||||
// STRING_PROCEDURE -------> the SQL code that defined the stored procedure as a single string value
|
||||
// STRING_DROP_CODE -------> the sql code that drops the current database object
|
||||
// STRING_TYPE_LIST -------> an associative array of associative arrays -- in the top level, the key is the name
|
||||
// of the parameter that points to a sub-array that contains the parameter direction
|
||||
// as the key, and the parameter type as the value. There should be an entry for each
|
||||
// parameter to be passed to the stored procedure/function.
|
||||
//
|
||||
// ------------------------------------------------------
|
||||
// | NOTE: IN params must precede INOUT and OUT params! |
|
||||
// ------------------------------------------------------
|
||||
//
|
||||
// STRING_SP_EVENT_TYPE ---> Assign one of the DB_EVENT constants to this field to indicate the type of
|
||||
// query the stored-procedure will execute.
|
||||
// NOTE: there is not a defined PDO::PARAM constant for type float: use string.
|
||||
// STRING_DESCRIPTION -----> clear-text definition of the procedure's purpose
|
||||
//
|
||||
// Note that all of these containers are required; empty containers should contain a null placeholder.
|
||||
//
|
||||
// When a stored procedure contains a join of two or more tables/views, the first table listed is considered
|
||||
// to be the "owning" table and the procedure will be declared in the class template for that table, but it will
|
||||
// not be duplicated in other template classes referenced in the join.
|
||||
//
|
||||
public ?array $dbObjects = [
|
||||
PDO_SQL => [
|
||||
[
|
||||
PDO_VERSION => 1.0,
|
||||
PDO_TABLE => 'gaTest_tst',
|
||||
PDO_SQL_FC => "
|
||||
--
|
||||
-- Table structure for table `gaTest_tst`
|
||||
--
|
||||
CREATE TABLE `gaTest_tst` (
|
||||
`id_tst` int(10) UNSIGNED NOT NULL,
|
||||
`testString_tst` varchar(255) DEFAULT NULL,
|
||||
`testDouble_tst` double DEFAULT NULL,
|
||||
`testInteger_tst` int(11) DEFAULT NULL,
|
||||
`testBoolean_tst` tinyint(1) UNSIGNED DEFAULT NULL,
|
||||
`notIndexedField_tst` int(11) DEFAULT NULL COMMENT 'do not index this field',
|
||||
`createdDate_tst` datetime DEFAULT NULL,
|
||||
`lastAccessedDate_tst` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
|
||||
`status_tst` varchar(32) DEFAULT NULL,
|
||||
`eventGUID_tst` char(36) DEFAULT NULL,
|
||||
`token_tst` char(36) NOT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
",
|
||||
PDO_SQL_UPDATE => "
|
||||
--
|
||||
-- Indexes for table `gaTest_tst`
|
||||
--
|
||||
ALTER TABLE `gaTest_tst`
|
||||
ADD PRIMARY KEY (`id_tst`),
|
||||
ADD UNIQUE KEY `gaTest_tst_token_tst_uindex` (`token_tst`),
|
||||
ADD KEY `gaTest_tst_createdDate_tst_status_tst_index` (`createdDate_tst`,`status_tst`),
|
||||
ADD KEY `gaTest_tst_eventGuid_tst_index` (`eventGUID_tst`),
|
||||
ADD KEY `gaTest_tst_lastAccessedDate_tst_index` (`lastAccessedDate_tst`),
|
||||
ADD KEY `testInteger_tst` (`testInteger_tst`),
|
||||
ADD KEY `testDouble_tst` (`testDouble_tst`),
|
||||
ADD KEY `testString_tst` (`testString_tst`(191));
|
||||
--
|
||||
-- AUTO_INCREMENT for dumped tables
|
||||
--
|
||||
|
||||
--
|
||||
-- AUTO_INCREMENT for table `gaTest_tst`
|
||||
--
|
||||
ALTER TABLE `gaTest_tst`
|
||||
MODIFY `id_tst` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;
|
||||
",
|
||||
/*
|
||||
* example query return:
|
||||
* ---------------------
|
||||
* ALTER TABLE gaTest_tst DROP INDEX gaTest_tst_createdDate_tst_status_tst_index, DROP INDEX
|
||||
* gaTest_tst_lastAccessedDate_tst_index, DROP INDEX testInteger_tst, DROP INDEX
|
||||
* gaTest_tst_eventGuid_tst_index, DROP INDEX testDouble_tst, DROP INDEX testString_tst;
|
||||
*
|
||||
* NOTE:
|
||||
* -----
|
||||
* The sql comment code tag (--) will be removed during mysqlConfig's run time processing
|
||||
*/
|
||||
STRING_DROP_CODE_IDX => "--
|
||||
SELECT CONCAT('ALTER TABLE ', `Table`, ' DROP INDEX ', GROUP_CONCAT(`Index` SEPARATOR ', DROP INDEX '),';' )
|
||||
FROM (
|
||||
SELECT table_name AS `Table`, index_name AS `Index`
|
||||
FROM information_schema.statistics
|
||||
WHERE INDEX_NAME != 'PRIMARY'
|
||||
AND table_schema = 'XXXDROP_DB_NAMEXXX'
|
||||
AND table_name = 'XXXDROP_TABLE_NAMEXXX'
|
||||
GROUP BY `Table`, `Index`) AS tmp
|
||||
GROUP BY `Table`;
|
||||
",
|
||||
STRING_DROP_CODE_DEV => "DROP TABLE IF EXISTS gaTest_tst;" // only executed if declared
|
||||
]
|
||||
],
|
||||
PDO_VIEWS => [
|
||||
'view_basic_gaTest_tst' => [
|
||||
STRING_VIEW =>
|
||||
"DROP VIEW IF EXISTS view_basic_gaTest_tst;
|
||||
CREATE VIEW view_basic_gaTest_tst AS
|
||||
SELECT token_tst, testString_tst, testDouble_tst, testInteger_tst, testBoolean_tst,
|
||||
notIndexedField_tst, status_tst, createdDate_tst, lastAccessedDate_tst, eventGUID_tst
|
||||
FROM gaTest_tst
|
||||
WHERE status_tst <> 'DELETED';",
|
||||
STRING_TYPE_LIST => null,
|
||||
STRING_DESCRIPTION => 'basic query'
|
||||
],
|
||||
'view_audit_gaTest_tst' => [
|
||||
STRING_VIEW =>
|
||||
"DROP VIEW IF EXISTS view_audit_gaTest_tst;
|
||||
CREATE VIEW view_audit_gaTest_tst AS
|
||||
SELECT token_tst, testString_tst, testDouble_tst, testInteger_tst, testBoolean_tst,
|
||||
notIndexedField_tst, status_tst, createdDate_tst, lastAccessedDate_tst, eventGUID_tst
|
||||
FROM gaTest_tst;",
|
||||
STRING_TYPE_LIST => null,
|
||||
STRING_DESCRIPTION => 'query for cross-broker queries by audit micro-service'
|
||||
]
|
||||
],
|
||||
PDO_PROCEDURES => [
|
||||
'testProc0' => [
|
||||
STRING_DROP_CODE_DEV => "DROP PROCEDURE IF EXISTS testProc0;",
|
||||
STRING_PROCEDURE =>
|
||||
"CREATE PROCEDURE testProc0()
|
||||
READS SQL DATA
|
||||
BEGIN
|
||||
SET @sqlString = 'SELECT COUNT(*) AS recordCount FROM gaTest_tst';
|
||||
|
||||
PREPARE sqlString from @sqlString;
|
||||
EXECUTE sqlString;
|
||||
DEALLOCATE PREPARE sqlString;
|
||||
END",
|
||||
STRING_TYPE_LIST => null,
|
||||
STRING_SP_EVENT_TYPE => DB_EVENT_SELECT,
|
||||
STRING_DESCRIPTION => 'stored procedure to return row-count of the table, demos a zero-param sp'
|
||||
],
|
||||
'testProc1' => [
|
||||
STRING_DROP_CODE_DEV => 'DROP PROCEDURE IF EXISTS testProc1;',
|
||||
STRING_PROCEDURE =>
|
||||
"CREATE PROCEDURE testProc1( IN targetValue INT )
|
||||
READS SQL DATA
|
||||
BEGIN
|
||||
SET @targetVal = targetValue;
|
||||
|
||||
SET @sqlString = CONCAT('
|
||||
SELECT testInteger_tst, count(*) as rowCount
|
||||
FROM gaTest_tst
|
||||
WHERE testInteger_tst is not null
|
||||
GROUP BY testInteger_tst
|
||||
HAVING rowCount > ', @targetVal, '
|
||||
ORDER BY rowCount DESC
|
||||
LIMIT 10');
|
||||
|
||||
PREPARE sqlStatement FROM @sqlString;
|
||||
EXECUTE sqlStatement;
|
||||
DEALLOCATE PREPARE sqlStatement;
|
||||
END",
|
||||
STRING_TYPE_LIST => [
|
||||
'targetValue' => [ STRING_IN => PDO::PARAM_INT ]
|
||||
],
|
||||
STRING_SP_EVENT_TYPE => DB_EVENT_SELECT,
|
||||
STRING_DESCRIPTION => 'stored procedure that return top-10 list of integer-field values by count for all values greater than the supplied input parameter'
|
||||
],
|
||||
'testProc2' => [
|
||||
STRING_DROP_CODE_DEV => 'DROP PROCEDURE IF EXISTS testProc2;',
|
||||
STRING_PROCEDURE =>
|
||||
"CREATE PROCEDURE testProc2( IN intVal INT, OUT avgDouble FLOAT, OUT stdDevDouble FLOAT )
|
||||
READS SQL DATA
|
||||
BEGIN
|
||||
SELECT AVG(testDouble_tst), STDDEV(testDouble_tst)
|
||||
INTO avgDouble, stdDevDouble
|
||||
FROM gaTest_tst
|
||||
WHERE testInteger_tst = intVal;
|
||||
END",
|
||||
STRING_TYPE_LIST => [
|
||||
'intVal' => [ STRING_IN => PDO::PARAM_INT ],
|
||||
'avgDouble' => [ STRING_OUT => PDO::PARAM_STR ],
|
||||
'stdDevDouble' => [ STRING_OUT => PDO::PARAM_STR]
|
||||
],
|
||||
STRING_SP_EVENT_TYPE => DB_EVENT_SELECT,
|
||||
STRING_DESCRIPTION => 'stored procedure that calculates the avg() and stddev() for the floats with a specified integer value'
|
||||
]
|
||||
],
|
||||
PDO_FUNCTIONS => [],
|
||||
PDO_EVENTS => [],
|
||||
PDO_TRIGGERS => []
|
||||
];
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// MIGRATION DECLARATIONS
|
||||
// ----------------------
|
||||
// Data in this section is used to handle migrations -- when we're pulling from legacy tables into the Namaste
|
||||
// framework. See online doc for more info.
|
||||
//=================================================================================================================
|
||||
|
||||
/**
|
||||
* The migration map is an associative array that maps the Namaste fields (keys) to the corresponding
|
||||
* (remote) legacy fields in the source table to be migrated to Namaste.
|
||||
*
|
||||
* For example, if we were migrating a mysql table in the legacy production database to Namaste::mongo, then
|
||||
* the keys of the migration map would be the Namaste::mongo->fieldNames and the values would be the mysql
|
||||
* column names in the legacy table.
|
||||
*
|
||||
* If there is a value which cannot be mapped to a key, then set it to null.
|
||||
*
|
||||
* Fields that will be dropped in the migration are not listed as values or as keys.
|
||||
*
|
||||
* This map will only exist in the template object and will never be imported into the class widget.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationMap = null;
|
||||
|
||||
/*
|
||||
* the migrationSortKey defines the SOURCE field by which the fetch query will be sorted. ALL sort fields are
|
||||
* in ASC order so all we need to list here is the name of the field -- which MUST BE IN THE SOURCE TABLE.
|
||||
*
|
||||
* Populating this field may require preliminary examination of the data - what we want is a field that has
|
||||
* zero NULL values.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?string $migrationSortKey = '';
|
||||
|
||||
/*
|
||||
* The migrationStatusKey defines the status field/column in the source table -- if the user requires that
|
||||
* soft-deleted records not be migrated, then this field must be set. Otherwise, set the value to null.
|
||||
*
|
||||
* The format is in the form of a key-value paired array. The key specifies the name of the column and the value
|
||||
* specifies the "deleted" value that, if found, will cause that row from the SOURCE data to be omitted from the
|
||||
* DESTINATION table.
|
||||
*
|
||||
* e.g.: $migrationStatusKV = [ 'some_field' => 'deleted' ]
|
||||
*
|
||||
* Note that both the key and the value are case-sensitive!
|
||||
*
|
||||
* This is an optional field.
|
||||
*
|
||||
*/
|
||||
public ?string $migrationStatusKV = null;
|
||||
|
||||
// The $migrationSourceSchema defines the remote schema for the source table, and is set in the constructor
|
||||
public ?string $migrationSourceSchema;
|
||||
|
||||
// The source table in the remote repos (default defined in the XML) must be declared here, set in the constructor
|
||||
public ?string $migrationSourceTable;
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [ OPERAND_NULL => [ OPERATOR_LT => [ null ] ] ],
|
||||
DB_STATUS => [ OPERAND_NULL => [ OPERATOR_EQ => [ STATUS_ACTIVE ]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-13-17 mks CORE-562: original coding
|
||||
* 09-09-19 mks DB-111: initialization of migration members moved to constructor b/c IDE warnings.
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
// these next two lines are so that the IDE doesn't flag the variable declarations as unused </facePalm>
|
||||
$this->migrationSourceSchema = '';
|
||||
$this->migrationSourceTable = '';
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/** @noinspection PhpUnused */
|
||||
/**
|
||||
* buildTestData() -- public static method
|
||||
*
|
||||
* this method is used to build an array structure of random data. There are two parameters to the method:
|
||||
*
|
||||
* $_records specifies the number of records to return to the calling client
|
||||
* $_incomplete indicates if we want to generate a partial (not all the fields are provided) record
|
||||
*
|
||||
* The $_incomplete parameter allows us to test the PDO class ability to successfully process partial payloads
|
||||
* on new record creation.
|
||||
*
|
||||
* The input parameter specifies how many records (indexes in the array) should be returned to the calling client
|
||||
* and should be a reasonable integer between one and one-hundred (1 - 100). If the passed-value for the number
|
||||
* of records is outside of this range, on either side, then the passed-value will be replaced with the range
|
||||
* limit for the appropriate "side".
|
||||
*
|
||||
* We then spin through a loop which populates an indexed array with the elements, from the test class,
|
||||
* with the appropriate extension as the sub-array key value.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @param int $_records
|
||||
* @param bool $_incomplete
|
||||
* @return array
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-13-17 mks CORE-562: original coding
|
||||
* 10-23-17 mks CORE_585: incomplete option added to skip some of the fields
|
||||
* 11-06-20 mks DB-171: ensuring that the test string length cannot be > 255 (max width of table column)
|
||||
*
|
||||
*/
|
||||
public static function buildTestData(int $_records = 1, bool $_incomplete = false): array
|
||||
{
|
||||
if ($_records < 1) $_records = 1;
|
||||
if ($_records > 1000) $_records = 1000;
|
||||
$retData = null;
|
||||
mt_srand();
|
||||
for ($index = 0; $index < $_records; $index++) {
|
||||
$sentenceCount = mt_rand(1, 20);
|
||||
$coinToss = ($_incomplete) ? mt_rand(0, 1) : 1;
|
||||
if ($coinToss) $retData[$index][CM_TST_FIELD_TEST_INT] = $sentenceCount;
|
||||
$coinToss = ($_incomplete) ? mt_rand(0, 1) : 1;
|
||||
if ($coinToss) $retData[$index][CM_TST_FIELD_TEST_DOUBLE] = floatval((1 / mt_rand(1, 10000)) * 100);
|
||||
$coinToss = ($_incomplete) ? mt_rand(0, 1) : 1;
|
||||
if ($coinToss) {
|
||||
$retData[$index][CM_TST_FIELD_TEST_STRING] = lorumIpsum($sentenceCount, 0);
|
||||
if (strlen($retData[$index][CM_TST_FIELD_TEST_STRING]) > 255)
|
||||
$retData[$index][CM_TST_FIELD_TEST_STRING] = substr($retData[$index][CM_TST_FIELD_TEST_STRING], 0, strpos(wordwrap($retData[$index][CM_TST_FIELD_TEST_STRING], 255), "\n"));
|
||||
|
||||
}
|
||||
$retData[$index][CM_TST_FIELD_TEST_BOOL] = intval(mt_rand(0,1));
|
||||
}
|
||||
return ($retData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-13-17 mks CORE-562: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 09-13-17 mks CORE-562: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// empty by design
|
||||
}
|
||||
|
||||
}
|
||||
478
classes/templates/gatTransactions.class.inc
Normal file
478
classes/templates/gatTransactions.class.inc
Normal file
@@ -0,0 +1,478 @@
|
||||
<?php
|
||||
/** @noinspection PhpUnused */
|
||||
|
||||
/**
|
||||
* Class gatTransactions -- mongo collection template for Namaste
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-11-20 mks DB-147: original coding
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
|
||||
class gatTransactions
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_APPSERVER; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_TRANSACTIONS; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_TRANSACTIONS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_TRANSACTIONS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NONDESTRUCTIVE; // set to AUDIT_value constant (nondestructive = reads(yes))
|
||||
public bool $setJournaling = true; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = true; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = false; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique pkey exposed externally and is REQUIRED
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER, // epoch time
|
||||
TRANSACTIONS_ORDER_ID => DATA_TYPE_INTEGER,
|
||||
TRANSACTIONS_TYPE => DATA_TYPE_STRING,
|
||||
TRANSACTIONS_DESCRIPTION => DATA_TYPE_STRING,
|
||||
TRANSACTIONS_AMOUNT => DATA_TYPE_DOUBLE,
|
||||
TRANSACTIONS_EVENT_DATE => DATA_TYPE_DATETIME,
|
||||
TRANSACTIONS_START_DATE => DATA_TYPE_DATETIME,
|
||||
TRANSACTIONS_END_DATE => DATA_TYPE_DATETIME,
|
||||
TRANSACTIONS_META_DATA => DATA_TYPE_ARRAY,
|
||||
TRANSACTIONS_MD_TRAVEL_END_DATE => DATA_TYPE_DATETIME,
|
||||
TRANSACTIONS_MD_PARTNER => DATA_TYPE_STRING,
|
||||
TRANSACTION_MD_PRODUCT_ID => DATA_TYPE_INTEGER,
|
||||
TRANSACTIONS_MD_TRAVEL_START_DATE => DATA_TYPE_DATETIME,
|
||||
TRANSACTIONS_MD_CUSTOMER_ID => DATA_TYPE_INTEGER,
|
||||
TRANSACTIONS_MD_OFFER_NUMBER => DATA_TYPE_INTEGER,
|
||||
TRANSACTIONS_MD_ENV => DATA_TYPE_STRING,
|
||||
TRANSACTIONS_DEST_CITY_NAME => DATA_TYPE_STRING,
|
||||
TRANSACTIONS_DEST_STATE_CODE => DATA_TYPE_STRING,
|
||||
TRANSACTIONS_DEST_COUNTRY_CODE => DATA_TYPE_STRING,
|
||||
TRANSACTIONS_DONOR_ID => DATA_TYPE_INTEGER,
|
||||
TRANSACTIONS_CID => DATA_TYPE_STRING,
|
||||
TRANSACTIONS_CAUSE_TITLE => DATA_TYPE_STRING
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, MONGO_ID
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_CREATED, DB_STATUS, DB_TOKEN
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_CREATED => -1
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Sparse indexes only add the row to the index if the column referenced satisfies the conditions specified
|
||||
// in the query condition (expr2).
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1 // MONGO_TOKEN should always appear
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null; // ttl indexes appear in $indexFields
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
DB_TOKEN => CM_TST_TOKEN,
|
||||
DB_STATUS => CM_TST_FIELD_TEST_STATUS,
|
||||
DB_EVENT_GUID => CM_TST_EVENT_GUID,
|
||||
DB_CREATED => CM_TRANSACTIONS_CREATED_AT,
|
||||
DB_ACCESSED => CM_TRANSACTIONS_UPDATED_AT,
|
||||
TRANSACTIONS_ORDER_ID => CM_TRANSACTIONS_ORDER_ID,
|
||||
TRANSACTIONS_TYPE => CM_TRANSACTIONS_TYPE,
|
||||
TRANSACTIONS_DESCRIPTION => CM_TRANSACTIONS_DESCRIPTION,
|
||||
TRANSACTIONS_AMOUNT => CM_TRANSACTIONS_AMOUNT,
|
||||
TRANSACTIONS_EVENT_DATE => CM_TRANSACTIONS_EVENT_DATE,
|
||||
TRANSACTIONS_START_DATE => CM_TRANSACTIONS_START_DATE,
|
||||
TRANSACTIONS_END_DATE => CM_TRANSACTIONS_END_DATE,
|
||||
TRANSACTIONS_META_DATA => CM_TRANSACTIONS_META_DATA,
|
||||
TRANSACTIONS_MD_TRAVEL_END_DATE => CM_TRANSACTIONS_MD_TRAVEL_END_DATE,
|
||||
TRANSACTIONS_MD_PARTNER => CM_TRANSACTIONS_MD_PARTNER,
|
||||
TRANSACTION_MD_PRODUCT_ID => CM_TRANSACTIONS_MD_PRODUCT_ID,
|
||||
TRANSACTIONS_MD_TRAVEL_START_DATE => CM_TRANSACTIONS_MD_TRAVEL_START_DATE,
|
||||
TRANSACTIONS_MD_CUSTOMER_ID => CM_TRANSACTIONS_MD_CUSTOMER_ID,
|
||||
TRANSACTIONS_MD_OFFER_NUMBER => CM_TRANSACTIONS_MD_OFFER_NUM,
|
||||
TRANSACTIONS_MD_ENV => CM_TRANSACTIONS_MD_ENV,
|
||||
TRANSACTIONS_DEST_CITY_NAME => CM_TRANSACTIONS_DEST_CITY_NAME,
|
||||
TRANSACTIONS_DEST_STATE_CODE => CM_TRANSACTIONS_DEST_STATE_CODE,
|
||||
TRANSACTIONS_DEST_COUNTRY_CODE => CM_TRANSACTIONS_DEST_COUNTRY_CODE,
|
||||
TRANSACTIONS_DONOR_ID => CM_TRANSACTIONS_DONOR_ID,
|
||||
TRANSACTIONS_CID => CM_TRANSACTIONS_CID,
|
||||
TRANSACTIONS_CAUSE_TITLE => CM_TRANSACTIONS_CAUSE_TITLE
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = null;
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [OPERAND_NULL => [OPERATOR_LT => [null]]],
|
||||
DB_STATUS => [OPERAND_NULL => [OPERATOR_EQ => [STATUS_ACTIVE]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-11-20 mks DB-147: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-11-20 mks DB-147: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-11-20 mks DB-147: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
660
classes/templates/gatUsers.class.inc
Normal file
660
classes/templates/gatUsers.class.inc
Normal file
@@ -0,0 +1,660 @@
|
||||
<?php
|
||||
/** @noinspection PhpUnused */
|
||||
/**
|
||||
* Class gatUsers -- mongo class
|
||||
*
|
||||
* This class is used to store the user PII data necessary for a GA user account. This collection also stores internal
|
||||
* accounts. (Administrative, CSR, etc.)
|
||||
*
|
||||
* In the legacy (Parse) collection, there were 78 columns, not including the proprietary ACL column. In the first
|
||||
* pass of this migration, we've grouped the original entries into five sub-collections.
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-04-20 mks DB-147: original coding
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
|
||||
class gatUsers
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version; not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_TERCERO; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_USERS; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_USERS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_USERS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = false; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = false; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NONDESTRUCTIVE; // set to AUDIT_value constant (nondestructive = reads(yes))
|
||||
public bool $setJournaling = true; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = true; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = false; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_INTEGER,
|
||||
USER_ACCOUNT_SSO => DATA_TYPE_STRING,
|
||||
USER_AUTH_DATA => DATA_TYPE_OBJECT,
|
||||
USER_EMAIL_VERIFIED => DATA_TYPE_BOOL,
|
||||
USER_FBID => DATA_TYPE_STRING,
|
||||
USER_VERIFIED_HUMAN => DATA_TYPE_BOOL,
|
||||
USER_MEMBERSHIP_PLAN => DATA_TYPE_STRING,
|
||||
USER_NOTES => DATA_TYPE_STRING,
|
||||
USER_PARTNER_API_KEY => DATA_TYPE_STRING,
|
||||
USER_PASSWORD => DATA_TYPE_STRING,
|
||||
USER_PASSWORD_UPDATED => DATA_TYPE_INTEGER,
|
||||
USER_PASSWORD_LAST_THREE => DATA_TYPE_ARRAY,
|
||||
USER_PROMO_SIGN_UP_ID => DATA_TYPE_INTEGER,
|
||||
USER_TEMP_PASSWORD => DATA_TYPE_STRING,
|
||||
USER_TZ => DATA_TYPE_DOUBLE,
|
||||
USER_LEAP_CONVERTED => DATA_TYPE_BOOL,
|
||||
USER_USERNAME => DATA_TYPE_STRING,
|
||||
USER_WEBHOOK_RETRIES => DATA_TYPE_INTEGER,
|
||||
USER_TYPE => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS => DATA_TYPE_ARRAY,
|
||||
USER_FINANCIALS_TOTAL_DONATIONS => DATA_TYPE_DOUBLE,
|
||||
USER_FINANCIALS_TOTAL_EARNINGS => DATA_TYPE_DOUBLE,
|
||||
USER_FINANCIALS_CASHBACK_BANK => DATA_TYPE_INTEGER,
|
||||
USER_FINANCIALS_CASHBACK_DONATION => DATA_TYPE_INTEGER,
|
||||
USER_FINANCIALS_CURRENT_BALANCE => DATA_TYPE_DOUBLE,
|
||||
USER_FINANCIALS_EARNING_TIER => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_PAYMENTS => DATA_TYPE_ARRAY,
|
||||
USER_FINANCIALS_PAYMENTS_ADDRESS1 => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_PAYMENTS_ADDRESS2 => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_PAYMENTS_CITY => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_PAYMENTS_COUNTRY => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_PAYMENTS_FULL_NAME => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_PAYMENTS_PLAN => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_PAYMENTS_STATE => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_PAYMENTS_STATUS => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_PAYMENTS_ZIP => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_PAYMENTS_VERIFIED => DATA_TYPE_BOOL,
|
||||
USER_FINANCIALS_PAYMENTS_META => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_PAYMENTS_TYPE => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_PENDING_BALANCE => DATA_TYPE_DOUBLE,
|
||||
USER_FINANCIALS_CUSTOMER_ID => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_STRIPE_RECIPIENT_VERIFIED => DATA_TYPE_BOOL,
|
||||
USER_FINANCIALS_TIN_FINGERPRINT => DATA_TYPE_STRING,
|
||||
USER_FINANCIALS_TIN_TYPE => DATA_TYPE_STRING,
|
||||
USER_SPORTS => DATA_TYPE_ARRAY,
|
||||
USER_SPORTS_FAV_ATHLETES => DATA_TYPE_OBJECT,
|
||||
USER_SPORTS_FAV_TEAMS => DATA_TYPE_OBJECT,
|
||||
USER_SPORTS_FAV_SPORTS => DATA_TYPE_OBJECT,
|
||||
USER_CHARITIES => DATA_TYPE_ARRAY,
|
||||
USER_CHARITIES_SELECTED_CAMPAIGN => DATA_TYPE_INTEGER,
|
||||
USER_CHARITIES_SELECTED_CAMPAIGN_META => DATA_TYPE_INTEGER,
|
||||
USER_CHARITIES_SELECTED_CAMPAIGN_TITLE => DATA_TYPE_STRING,
|
||||
USER_REFERRALS => DATA_TYPE_ARRAY,
|
||||
USER_REFERRALS_EARNINGS => DATA_TYPE_INTEGER,
|
||||
USER_REFERRALS_CLICKS => DATA_TYPE_INTEGER,
|
||||
USER_REFERRALS_EARNINGS_PENDING => DATA_TYPE_INTEGER,
|
||||
USER_REFERRALS_SIGNUPS => DATA_TYPE_INTEGER,
|
||||
USER_REFERRALS_RID => DATA_TYPE_STRING,
|
||||
USER_PII => DATA_TYPE_ARRAY,
|
||||
USER_PII_ADDRESS => DATA_TYPE_STRING,
|
||||
USER_PII_AGE_RANGE => DATA_TYPE_STRING,
|
||||
USER_PII_BIRTHDAY => DATA_TYPE_DATETIME,
|
||||
USER_PII_COUNTRY_CODE => DATA_TYPE_STRING,
|
||||
USER_PII_EMAIL => DATA_TYPE_STRING,
|
||||
USER_PII_SECONDARY_EMAIL => DATA_TYPE_STRING,
|
||||
USER_PII_FNAME => DATA_TYPE_STRING,
|
||||
USER_PII_GENDER => DATA_TYPE_STRING,
|
||||
USER_PII_HOMETOWN => DATA_TYPE_STRING,
|
||||
USER_PII_LANGUAGES => DATA_TYPE_OBJECT,
|
||||
USER_PII_LNAME => DATA_TYPE_STRING,
|
||||
USER_PII_LEGAL_NAME => DATA_TYPE_STRING,
|
||||
USER_PII_LOCALE => DATA_TYPE_STRING,
|
||||
USER_PII_LOCATION => DATA_TYPE_STRING,
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER // epoch time
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, DB_STATUS
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_CREATED, DB_EVENT_GUID, DB_ACCESSED, MONGO_ID, DB_STATUS
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_TOKEN, DB_CREATED, DB_STATUS, DB_EVENT_GUID, USER_PII_EMAIL, USER_PII_SECONDARY_EMAIL
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = [ 'emailsIndex', 'activePartnersIndex' ];
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_TOKEN => 1,
|
||||
DB_CREATED => -1,
|
||||
DB_STATUS => 1,
|
||||
DB_EVENT_GUID => 1
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = [
|
||||
'emailsIndex' => [ USER_PII_EMAIL => 1, USER_PII_SECONDARY_EMAIL => 1 ],
|
||||
'activePartnersIndex' => [ USER_PARTNER_API_KEY => 1, DB_STATUS => 1 ]
|
||||
];
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Sparse indexes only add the row to the index if the column referenced satisfies the conditions specified
|
||||
// in the query condition (expr2).
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1, // MONGO_TOKEN should always appear
|
||||
DB_EVENT_GUID => 1,
|
||||
USER_PII_EMAIL => 1
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
// cache maps are required for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
DB_TOKEN => CM_TOKEN,
|
||||
DB_CREATED => CM_DATE_CREATED,
|
||||
DB_ACCESSED => CM_DATE_ACCESSED,
|
||||
DB_STATUS => CM_STATUS,
|
||||
DB_EVENT_GUID => CM_EVENT_GUID,
|
||||
USER_ACCOUNT_SSO => CM_USER_ACCOUNT,
|
||||
USER_AUTH_DATA => CM_USER_API_DATA,
|
||||
USER_EMAIL_VERIFIED => CM_USER_EMAIL_VALIDATED,
|
||||
USER_FBID => CM_USER_FB_KEY,
|
||||
USER_VERIFIED_HUMAN => CM_USER_HUMAN_VALIDATED,
|
||||
USER_MEMBERSHIP_PLAN => CM_USER_MEMBER_PLAN,
|
||||
USER_NOTES => CM_USER_NOTES,
|
||||
USER_PASSWORD => CM_USER_PASSWORD,
|
||||
USER_PROMO_SIGN_UP_ID => CM_USER_PROMO_ID,
|
||||
USER_TEMP_PASSWORD => CM_USER_TEMPORARY_PWD,
|
||||
USER_TZ => CM_USER_TIMEZONE,
|
||||
USER_LEAP_CONVERTED => CM_USER_LEAP_CONVERTED,
|
||||
USER_USERNAME => CM_USER_NAME,
|
||||
USER_WEBHOOK_RETRIES => CM_USER_WEBHOOK_ATTEMPTS,
|
||||
USER_TYPE => CM_USER_TYPE,
|
||||
USER_FINANCIALS => CM_USER_FINANCIALS,
|
||||
USER_FINANCIALS_TOTAL_DONATIONS => CM_USER_FINANCIALS_DONATIONS,
|
||||
USER_FINANCIALS_TOTAL_EARNINGS => CM_USER_FINANCIALS_EARNINGS,
|
||||
USER_FINANCIALS_CASHBACK_BANK => CM_USER_FINANCIALS_CB_BANK,
|
||||
USER_FINANCIALS_CASHBACK_DONATION => CM_USER_FINANCIALS_CB_DONATIONS,
|
||||
USER_FINANCIALS_CURRENT_BALANCE => CM_USER_FINANCIALS_CURR_BAL,
|
||||
USER_FINANCIALS_EARNING_TIER => CM_USER_FINANCIALS_EARNING_TIER,
|
||||
USER_FINANCIALS_PAYMENTS => CM_USER_FINANCIALS_PAYMENTS,
|
||||
USER_FINANCIALS_PAYMENTS_ADDRESS1 => USER_FINANCIALS_PAYMENTS_ADDRESS1,
|
||||
USER_FINANCIALS_PAYMENTS_ADDRESS2 => CM_USER_FINANCIALS_PAYMENTS_ADDR2,
|
||||
USER_FINANCIALS_PAYMENTS_CITY => CM_USER_FINANCIALS_PAYMENTS_CITY,
|
||||
USER_FINANCIALS_PAYMENTS_COUNTRY => CM_USER_FINANCIALS_PAYMENTS_COUNTRY,
|
||||
USER_FINANCIALS_PAYMENTS_FULL_NAME => CM_USER_FINANCIALS_PAYMENTS_FNAME,
|
||||
USER_FINANCIALS_PAYMENTS_PLAN => CM_USER_FINANCIALS_PAYMENTS_PLAN,
|
||||
USER_FINANCIALS_PAYMENTS_STATE => CM_USER_FINANCIALS_PAYMENTS_STATE,
|
||||
USER_FINANCIALS_PAYMENTS_STATUS => CM_USER_FINANCIALS_PAYMENTS_STATUS,
|
||||
USER_FINANCIALS_PAYMENTS_ZIP => CM_USER_FINANCIALS_PAYMENTS_ZIP,
|
||||
USER_FINANCIALS_PAYMENTS_VERIFIED => CM_USER_FINANCIALS_PAYMENTS_VALIDATED,
|
||||
USER_FINANCIALS_PAYMENTS_META => CM_USER_FINANCIALS_PAYMENTS_METADATA,
|
||||
USER_FINANCIALS_PAYMENTS_TYPE => USER_FINANCIALS_PAYMENTS_TYPE,
|
||||
USER_FINANCIALS_PENDING_BALANCE => CM_USER_FINANCIALS_PENDING_BALANCE,
|
||||
USER_FINANCIALS_CUSTOMER_ID => CM_USER_FINANCIALS_CUSTOMER_ID,
|
||||
USER_FINANCIALS_STRIPE_RECIPIENT_VERIFIED => CM_USER_FINANCIALS_STRIPE_VERIFIED,
|
||||
USER_FINANCIALS_TIN_FINGERPRINT => CM_USER_FINANCIALS_TIN_IDENTIFIER,
|
||||
USER_FINANCIALS_TIN_TYPE => CM_USER_FINANCIALS_TIN_TYPE,
|
||||
USER_SPORTS => CM_USER_SPORTS,
|
||||
USER_SPORTS_FAV_ATHLETES => CM_USER_SPORTS_FAVE_ATHLETES,
|
||||
USER_SPORTS_FAV_TEAMS => CM_USER_SPORTS_FAVE_TEAMS,
|
||||
USER_SPORTS_FAV_SPORTS => CM_USER_SPORTS_FAVE_SPORTS,
|
||||
USER_CHARITIES => CM_USER_CHARITIES,
|
||||
USER_CHARITIES_SELECTED_CAMPAIGN => CM_USER_CHARITIES_SEL_CAMPAIGN,
|
||||
USER_CHARITIES_SELECTED_CAMPAIGN_META => CM_USER_CHARITIES_SEL_CAMPAIGN_META,
|
||||
USER_CHARITIES_SELECTED_CAMPAIGN_TITLE => CM_USER_CHARITIES_SEL_CAMPAIGN_TITLE,
|
||||
USER_REFERRALS => CM_USER_REFERRALS,
|
||||
USER_REFERRALS_EARNINGS => CM_USER_REFERRALS_EARNINGS,
|
||||
USER_REFERRALS_CLICKS => CM_USER_REFERRALS_CLICKS,
|
||||
USER_REFERRALS_EARNINGS_PENDING => CM_USER_REFERRALS_PENDING_EARNINGS,
|
||||
USER_REFERRALS_SIGNUPS => CM_USER_REFERRALS_SIGNUPS,
|
||||
USER_REFERRALS_RID => CM_USER_REFERRALS_ID,
|
||||
USER_PII => CM_USER_PII,
|
||||
USER_PII_ADDRESS => CM_USER_PII_ADDR,
|
||||
USER_PII_AGE_RANGE => CM_USER_PII_AGE_RANGE,
|
||||
USER_PII_BIRTHDAY => CM_USER_PII_DOB,
|
||||
USER_PII_COUNTRY_CODE => CM_USER_PII_COUNTRY_CODE,
|
||||
USER_PII_EMAIL => CM_USER_PII_EMAIL,
|
||||
USER_PII_SECONDARY_EMAIL => CM_USER_PII_ALT_EMAIL,
|
||||
USER_PII_FNAME => CM_USER_PII_FNAME,
|
||||
USER_PII_GENDER => CM_USER_PII_GENDER,
|
||||
USER_PII_HOMETOWN => CM_USER_PII_HOMETOWN,
|
||||
USER_PII_LANGUAGES => CM_USER_PII_LANGUAGES,
|
||||
USER_PII_LNAME => CM_USER_PII_LNAME,
|
||||
USER_PII_LEGAL_NAME => CM_USER_PII_LEGAL_NAME,
|
||||
USER_PII_LOCALE => CM_USER_PII_LOCALE,
|
||||
USER_PII_LOCATION => CM_USER_PII_LOCATION
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as the associative array: $exposedFields. Only those fields,
|
||||
* enumerated within this container, will be exposed to the client.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = [
|
||||
USER_SPORTS => [
|
||||
USER_SPORTS_FAV_ATHLETES,
|
||||
USER_SPORTS_FAV_TEAMS,
|
||||
USER_SPORTS_FAV_SPORTS
|
||||
],
|
||||
USER_CHARITIES => [
|
||||
USER_CHARITIES_SELECTED_CAMPAIGN,
|
||||
USER_CHARITIES_SELECTED_CAMPAIGN_META,
|
||||
USER_CHARITIES_SELECTED_CAMPAIGN_TITLE
|
||||
],
|
||||
USER_REFERRALS => [
|
||||
USER_REFERRALS_EARNINGS,
|
||||
USER_REFERRALS_CLICKS,
|
||||
USER_REFERRALS_EARNINGS_PENDING,
|
||||
USER_REFERRALS_SIGNUPS,
|
||||
USER_REFERRALS_RID
|
||||
],
|
||||
USER_PII => [
|
||||
USER_PII_ADDRESS,
|
||||
USER_PII_AGE_RANGE,
|
||||
USER_PII_BIRTHDAY,
|
||||
USER_PII_COUNTRY_CODE,
|
||||
USER_PII_EMAIL,
|
||||
USER_PII_FNAME,
|
||||
USER_PII_GENDER,
|
||||
USER_PII_HOMETOWN,
|
||||
USER_PII_LANGUAGES,
|
||||
USER_PII_LNAME,
|
||||
USER_PII_LEGAL_NAME,
|
||||
USER_PII_LOCALE,
|
||||
USER_PII_LOCATION
|
||||
],
|
||||
USER_FINANCIALS => [
|
||||
USER_FINANCIALS_TOTAL_DONATIONS,
|
||||
USER_FINANCIALS_TOTAL_EARNINGS,
|
||||
USER_FINANCIALS_CASHBACK_BANK,
|
||||
USER_FINANCIALS_CASHBACK_DONATION,
|
||||
USER_FINANCIALS_CURRENT_BALANCE,
|
||||
USER_FINANCIALS_EARNING_TIER,
|
||||
USER_FINANCIALS_PENDING_BALANCE,
|
||||
USER_FINANCIALS_CUSTOMER_ID,
|
||||
USER_FINANCIALS_STRIPE_RECIPIENT_VERIFIED,
|
||||
USER_FINANCIALS_TIN_FINGERPRINT,
|
||||
USER_FINANCIALS_TIN_TYPE,
|
||||
USER_FINANCIALS_PAYMENTS // <--- note that this is a sub-heading within a sub-heading |
|
||||
], // |
|
||||
USER_FINANCIALS_PAYMENTS => [ // <---------------------------------------------------------|
|
||||
USER_FINANCIALS_PAYMENTS_ADDRESS1,
|
||||
USER_FINANCIALS_PAYMENTS_ADDRESS2,
|
||||
USER_FINANCIALS_PAYMENTS_CITY,
|
||||
USER_FINANCIALS_PAYMENTS_COUNTRY,
|
||||
USER_FINANCIALS_PAYMENTS_FULL_NAME,
|
||||
USER_FINANCIALS_PAYMENTS_PLAN,
|
||||
USER_FINANCIALS_PAYMENTS_STATE,
|
||||
USER_FINANCIALS_PAYMENTS_STATUS,
|
||||
USER_FINANCIALS_PAYMENTS_ZIP,
|
||||
USER_FINANCIALS_PAYMENTS_VERIFIED,
|
||||
USER_FINANCIALS_PAYMENTS_META,
|
||||
USER_FINANCIALS_PAYMENTS_TYPE
|
||||
]
|
||||
];
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [OPERAND_NULL => [OPERATOR_LT => [null]]],
|
||||
DB_STATUS => [OPERAND_NULL => [OPERATOR_EQ => [STATUS_ACTIVE]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* Constructor in this template not only registers the shutdown method, but also allows us to generate a custom
|
||||
* GUID string during instantiation by use of the input parameters:
|
||||
*
|
||||
* $_getGUID - boolean, defaults to false but, if true, will generate a GUID value and store it in the class member
|
||||
* $_lc - boolean, defaults to false but, if true, will generate a GUID using lower-case alpha characters
|
||||
*
|
||||
* If we generate a GUID on instantiation, the GUID will be stored in the class member. This allows us to both
|
||||
* instantiate a session class object and a GUID value, (the most requested, post-instantiation, action), at the
|
||||
* same time. All the efficient.
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-04-20 mks DB-147: original coding
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-04-20 mks DB-147: original coding
|
||||
*
|
||||
* @version 1.0
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 02-04-20 mks DB-147: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// move on lookie-loo....
|
||||
}
|
||||
|
||||
}
|
||||
469
classes/templates/gatWBList.class.inc
Normal file
469
classes/templates/gatWBList.class.inc
Normal file
@@ -0,0 +1,469 @@
|
||||
<?php
|
||||
/**
|
||||
* Class gatWBList -- template class for Giving Assistant's White/Black List collection.
|
||||
*
|
||||
* This is an tercero-class collection that records white and black-listed email addresses for the email validation
|
||||
* process.
|
||||
*
|
||||
* Rules are simple and as you would guess:
|
||||
* If an email is white listed then the email is always sent
|
||||
* elseif the email is black listed then the email is never sent and generates a system event
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-18-20 mks DB-168: original coding
|
||||
*
|
||||
*/
|
||||
|
||||
class gatWBList
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version; not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_TERCERO; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_WBL; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_WBLIST; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_WBLIST_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = false; // set to false to allow partner instantiations
|
||||
public bool $setCache = false; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_DESTRUCTIVE; // set to AUDIT_value constant (nondestructive = reads(yes))
|
||||
public bool $setJournaling = true; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER, // epoch time
|
||||
// fields specific to systemEvents collection
|
||||
MONGO_WBL_TYPE => DATA_TYPE_BOOL, // 1 = white, 0 = black
|
||||
USER_PII_EMAIL => DATA_TYPE_STRING, // email expression to be matched
|
||||
MONGO_WBL_ADDED_BY => DATA_TYPE_STRING, // who added record to list
|
||||
META_SYSTEM_NOTES => DATA_TYPE_STRING // notes about the add event
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, DB_STATUS
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_CREATED, DB_EVENT_GUID, DB_ACCESSED, MONGO_ID, DB_STATUS,
|
||||
MONGO_WBL_TYPE, USER_PII_EMAIL, MONGO_WBL_ADDED_BY, META_SYSTEM_NOTES
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_TOKEN, DB_CREATED, DB_STATUS, DB_EVENT_GUID,
|
||||
MONGO_WBL_TYPE, USER_PII_EMAIL, MONGO_WBL_ADDED_BY, 'wblType',
|
||||
'wblEmail', 'wblCSR', 'wblEmailCSR'
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_TOKEN => 1,
|
||||
DB_CREATED => -1,
|
||||
DB_STATUS => 1,
|
||||
DB_EVENT_GUID => 1,
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = [
|
||||
'wblType' => [ MONGO_WBL_TYPE => 1, DB_STATUS => 1],
|
||||
'wblEmail' => [ USER_PII_EMAIL => 1, DB_STATUS => 1],
|
||||
'wblCSR' => [ MONGO_WBL_ADDED_BY => 1, DB_STATUS => 1],
|
||||
'wblEmailCSR' => [ USER_PII_EMAIL => 1, MONGO_WBL_ADDED_BY => 1, DB_STATUS => 1]
|
||||
];
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Sparse indexes only add the row to the index if the column referenced satisfies the conditions specified
|
||||
// in the query condition (expr2).
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1, // MONGO_TOKEN should always appear
|
||||
DB_EVENT_GUID => 1,
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
// cache maps are required for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
DB_TOKEN => CM_TOKEN,
|
||||
DB_CREATED => CM_DATE_CREATED,
|
||||
DB_ACCESSED => CM_DATE_ACCESSED,
|
||||
DB_STATUS => CM_STATUS,
|
||||
DB_EVENT_GUID => CM_EVENT_GUID,
|
||||
// collection-specific fields
|
||||
MONGO_WBL_TYPE => CM_WBL_TYPE,
|
||||
USER_PII_EMAIL => CM_WBL_EMAIL,
|
||||
MONGO_WBL_ADDED_BY => CM_WBL_ADDED_BY,
|
||||
META_SYSTEM_NOTES => CM_WBL_NOTES
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as the associative array: $exposedFields. Only those fields,
|
||||
* enumerated within this container, will be exposed to the client.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = null;
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [OPERAND_NULL => [OPERATOR_LT => [null]]],
|
||||
DB_STATUS => [OPERAND_NULL => [OPERATOR_EQ => [STATUS_ACTIVE]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-18-20 mks DB-168: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* Constructor in this template not only registers the shutdown method, but also allows us to generate a custom
|
||||
* GUID string during instantiation by use of the input parameters:
|
||||
*
|
||||
* $_getGUID - boolean, defaults to false but, if true, will generate a GUID value and store it in the class member
|
||||
* $_lc - boolean, defaults to false but, if true, will generate a GUID using lower-case alpha characters
|
||||
*
|
||||
* If we generate a GUID on instantiation, the GUID will be stored in the class member. This allows us to both
|
||||
* instantiate a session class object and a GUID value, (the most requested, post-instantiation, action), at the
|
||||
* same time. All the efficient.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-18-20 mks DB-168: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 08-18-20 mks DB-168: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// move on lookie-loo....
|
||||
}
|
||||
}
|
||||
527
classes/templates/gatWHC1ProdRegistrations.class.inc
Normal file
527
classes/templates/gatWHC1ProdRegistrations.class.inc
Normal file
@@ -0,0 +1,527 @@
|
||||
<?php
|
||||
/**
|
||||
* gatWHC1ProdRegistrations.class -- Namaste mySQL Data Template for WH Level: COOL
|
||||
*
|
||||
* This is the warehouse data template file for the Namaste mySQL version of product-registration.
|
||||
* This template was created for the purpose of testing mysql->mysql data warehousing.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 05-08-18 mks _INF-188: original coding
|
||||
* 01-15-20 mks DB-150: PHP7.4 class member type-casting
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
class gatWHC1ProdRegistrations
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...```
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_SEGUNDO; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_PDO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_WHC1_PROD_REG; // defines the clear-text template class name
|
||||
public string $collection = WH_COOL_PDO_PROD_REGS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_PDO_PROD_REGS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = false; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = false; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = false; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if class contains methods or migration
|
||||
public int $cacheTimer = 0; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
//
|
||||
// Note that for PDO-type tables, the data type is more ... homogeneous... e.g.: data types define the data
|
||||
// type only. It does not define the actual column type in-use. For example, there is no distinction made
|
||||
// between a tinyInt, Int, or BigInt. As far as the framework is concerned, they're all just integers.
|
||||
//
|
||||
public array $fields = [
|
||||
PDO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
PRG_TYPE => DATA_TYPE_STRING,
|
||||
PRG_IID => DATA_TYPE_STRING,
|
||||
PRG_EAV => DATA_TYPE_STRING,
|
||||
PRG_PLATFORM => DATA_TYPE_STRING,
|
||||
PRG_BROWSER => DATA_TYPE_STRING,
|
||||
PRG_MAJOR_VERSION => DATA_TYPE_INTEGER,
|
||||
PRG_MINOR_VERSION => DATA_TYPE_INTEGER,
|
||||
PRG_IS_MOBILE => DATA_TYPE_INTEGER,
|
||||
PRG_IS_TABLET => DATA_TYPE_INTEGER,
|
||||
PRG_FIRST_SEEN => DATA_TYPE_STRING,
|
||||
PRG_LAST_SEEN => DATA_TYPE_STRING,
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (string) exposed externally and is REQUIRED,
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_STRING, // dateTime type
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_STRING, // dateTime type
|
||||
//_________________________________________________________________________
|
||||
// UP TO HERE IS THE ORIGINAL DATA -- BELOW IS THE WH_CLASS-SPECIFIC DATA
|
||||
//-------------------------------------------------------------------------
|
||||
DB_WH_CREATED => DATA_TYPE_STRING,
|
||||
DB_WH_EVENT_GUID => DATA_TYPE_STRING,
|
||||
DB_WH_TOKEN => DATA_TYPE_STRING
|
||||
];
|
||||
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, PDO_ID, DB_WH_EVENT_GUID, DB_WH_CREATED, DB_WH_TOKEN
|
||||
];
|
||||
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public array $indexFields = [
|
||||
DB_CREATED => 1,
|
||||
DB_WH_TOKEN => 1,
|
||||
DB_WH_CREATED => 1,
|
||||
DB_WH_EVENT_GUID => 1
|
||||
];
|
||||
|
||||
|
||||
// the primary key index is declared in the class properties section as $setPKey
|
||||
|
||||
// unique indexes are to be used a values stored in these columns have to be unique to the table. Note that
|
||||
// null values are permissible in unique-index columns. Do not declare PDO_ID here, regardless of how badly
|
||||
// you may want to.
|
||||
public ?array $uniqueIndexes = [ DB_WH_TOKEN, DB_WH_EVENT_GUID ];
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index (index, multi)
|
||||
// the format for the single-field index declaration is a simple indexed array.
|
||||
public ?array $singleFields = [
|
||||
DB_CREATED
|
||||
];
|
||||
|
||||
// multi-column (or compound) indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME1, FIELD_NAME2, ..., FIELD_NAMEn ]]
|
||||
// where INDEX-NAME is a unique string
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
//
|
||||
// PDO compound-indexes are left-most indexes - if it cannot use the entire index, the db must be able to use
|
||||
// one, or more, of the left-most fields in the index.
|
||||
public ?array $compoundIndexes = [
|
||||
'whC1PRG-I1' => [ DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN ]
|
||||
];
|
||||
|
||||
|
||||
// NOTE: foreign-key indexes are not explicitly enumerated in a template -- that relationship is defined in the
|
||||
// schema for the table. Foreign-key indexes appear implicitly in the indexing declarations above.
|
||||
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = null;
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = [
|
||||
PRG_TYPE => 1,
|
||||
PRG_IID => 1,
|
||||
PRG_EAV => 1,
|
||||
PRG_PLATFORM => 1,
|
||||
PRG_BROWSER => 1,
|
||||
PRG_MAJOR_VERSION => 1,
|
||||
PRG_MINOR_VERSION => 1,
|
||||
PRG_IS_MOBILE => 1,
|
||||
PRG_IS_TABLET => 1,
|
||||
PRG_FIRST_SEEN => 1,
|
||||
PRG_LAST_SEEN => 1,
|
||||
DB_CREATED => 1, // epoch time
|
||||
DB_STATUS => 1, // record status
|
||||
DB_ACCESSED => 1, // epoch time
|
||||
DB_WH_EVENT_GUID => 1,
|
||||
DB_WH_CREATED => 1,
|
||||
DB_WH_TOKEN => 1
|
||||
];
|
||||
|
||||
|
||||
// in PDO-land, binary fields are your basic data blobs. All binary fields require special handling and so
|
||||
// need to be enumerated here as an indexed array.
|
||||
public ?array $binFields = null;
|
||||
|
||||
|
||||
// DB SQL:
|
||||
// -------
|
||||
// PDO SQL is stored in the template and is keyed by the current namaste version (defined in the XML file) during
|
||||
// execution of the deployment script. Each version denotes a container of SQL commands that will be executed
|
||||
// for the targeted version.
|
||||
//
|
||||
// SQL is versioned in parallel with the Namaste (XML->application->id->version) version. Each PDO_SQL
|
||||
// sub-container has several fields - one of which has the version identifier. When the deployment script
|
||||
// executes, the release versions are compared and, if they're an exact match, the SQL is submitted for execution.
|
||||
//
|
||||
// The PDO_SQL container consists of these sub-containers:
|
||||
//
|
||||
// PDO_SQL_VERSION --> this is a float value in the form of x.y as namaste only supports versions as a major
|
||||
// and minor release number. (Patch releases are minor release increments.)
|
||||
// PDO_TABLE --> string value containing the full table name.
|
||||
// PDO_SQL_FC --> the FC means "first commit" -- when the table is first created, it will execute the
|
||||
// SQL in this block, if it exists, and if the version number for the sub-container
|
||||
// exactly matched the version number in the configuration XML.
|
||||
// PDO_SQL_UPDATE --> When the sub-container PDO_SQL_VERSION value exactly matches the XML release value,
|
||||
// then the ALTER-TABLE sql in this update block will be executed.
|
||||
// STRING_DROP_CODE_IDX --> The boilerplate code for dropping the indexes of the table.
|
||||
// STRING_DROP_CODE_DEV --> For version 1.0 only, this points to code to drop the entire table.
|
||||
//
|
||||
// Again, containers themselves are indexed arrays under the PDO_SQL tag. Within the container, data is stored
|
||||
// as an associative array with the keys enumerated above.
|
||||
//
|
||||
//
|
||||
// DB OBJECTS:
|
||||
// -----------
|
||||
// DB objects are: views, procedures, functions and events.
|
||||
// All such objects assigned to a class are declared in this array under the appropriate header.
|
||||
// This is a safety-feature that prevents a one class (table) from invoking another class object.
|
||||
// The name of the object is stored as an indexed-array under the appropriate header.
|
||||
//
|
||||
// The format for these structures is basically the same. Each DBO is stored in an associative array with the
|
||||
// key defining the name of the object. Within each object, there are embedded associative arrays that have the
|
||||
// name of the object as the key and the object definition (text) and the value:
|
||||
//
|
||||
// objectType => [ objectName => [ objectContent ], ... ]
|
||||
//
|
||||
// Each created object should also have the directive to remove it's predecessor using a DROP statement.
|
||||
//
|
||||
// todo -- unset these objects post-instantiation so that schema is not revealed
|
||||
//
|
||||
// VIEWS:
|
||||
// ------
|
||||
// Every namaste table will have at least one view which limits the data fetched from the table. At a minimum,
|
||||
// the id_{ext} field is filtered from the resulting data set via the view. Other fields can be withheld as well
|
||||
// but that is something that is individually set-up for each table.
|
||||
//
|
||||
// The basic view has the following syntax for declaring it's name:
|
||||
// view_basic_{tableName_ext}
|
||||
// All views start with the word "view" so as to self-identify the object, followed by the view type which,
|
||||
// optimally, you should try to limit to a single, descriptive word.
|
||||
//
|
||||
// Following this label, which points to a sub-array containing three elements:
|
||||
// STRING_VIEW ----------> this is the SQL code that defines the view as a single string value
|
||||
// STRING_TYPE_LIST -----> null or an array of types that corresponds to variable markers ('?') in the sql
|
||||
// STRING_DESCRIPTION' --> a string that describes the purpose of the view.
|
||||
//
|
||||
// At a minimum, every class definition should contain at-least a basic view as all queries that don't specify
|
||||
// a named view or other DBO, will default to the the basic view in the FROM clause of the generated SQL.
|
||||
//
|
||||
// PROCEDURES:
|
||||
// -----------
|
||||
// For stored procedures, which are entirely optional, the array definition contains the following elements:
|
||||
// STRING_PROCEDURE -------> the SQL code that defined the stored procedure as a single string value
|
||||
// STRING_DROP_CODE -------> the sql code that drops the procedure (required for procedures!)
|
||||
// STRING_TYPE_LIST -------> an associative array of associative arrays -- in the top level, the key is the name
|
||||
// of the parameter that points to a sub-array that contains the parameter direction
|
||||
// as the key, and the parameter type as the value. There should be an entry for each
|
||||
// parameter to be passed to the stored procedure/function.
|
||||
//
|
||||
// ------------------------------------------------------
|
||||
// | NOTE: IN params must precede INOUT and OUT params! |
|
||||
// ------------------------------------------------------
|
||||
//
|
||||
// STRING_SP_EVENT_TYPE ---> Assign one of the DB_EVENT constants to this field to indicate the type of
|
||||
// query the stored-procedure will execute.
|
||||
// NOTE: there is not a defined PDO::PARAM constant for type float: use string.
|
||||
// STRING_DESCRIPTION -----> clear-text definition of the procedure's purpose
|
||||
//
|
||||
// Note that all of these containers are required; empty containers should contain a null placeholder.
|
||||
//
|
||||
// When a stored procedure contains a join of two or more tables/views, the first table listed is considered
|
||||
// to be the "owning" table and the procedure will be declared in the class template for that table, but it will
|
||||
// not be duplicated in other template classes referenced in the join.
|
||||
//
|
||||
public ?array $dbObjects = [
|
||||
PDO_SQL => [
|
||||
[
|
||||
PDO_VERSION => 1.0,
|
||||
PDO_TABLE => 'gaCoolProductRegistrations_prg',
|
||||
PDO_SQL_FC => "
|
||||
--
|
||||
-- Table structure for table `gaCoolProductRegistrations_prg`
|
||||
--
|
||||
|
||||
CREATE TABLE `gaCoolProductRegistrations_prg` (
|
||||
`id_prg` int(10) UNSIGNED NOT NULL,
|
||||
`type_prg` char(16) NOT NULL,
|
||||
`iid_prg` char(64) DEFAULT NULL,
|
||||
`eav_prg` char(16) DEFAULT NULL,
|
||||
`platform_prg` char(32) DEFAULT NULL,
|
||||
`browser_prg` char(32) DEFAULT NULL,
|
||||
`majorVersion_prg` int(11) UNSIGNED DEFAULT NULL,
|
||||
`minorVersion_prg` int(11) UNSIGNED DEFAULT NULL,
|
||||
`isMobile_prg` tinyint(1) DEFAULT NULL,
|
||||
`isTablet_prg` tinyint(1) UNSIGNED DEFAULT NULL,
|
||||
`firstSeen_prg` datetime DEFAULT NULL,
|
||||
`lastSeen_prg` datetime DEFAULT NULL,
|
||||
`token_prg` char(36) DEFAULT NULL,
|
||||
`eventGuid_prg` char(36) DEFAULT NULL,
|
||||
`createdDate_prg` datetime DEFAULT NULL COMMENT 'replaces kinsert_date',
|
||||
`lastAccessedDate_prg` datetime DEFAULT NULL COMMENT 'replaces kupdate_date',
|
||||
`status_prg` varchar(25) DEFAULT NULL,
|
||||
`whCreated_prg` datetime DEFAULT NULL,
|
||||
`whEventGuid_prg` char(36) DEFAULT NULL,
|
||||
`whToken_prg` char(36) DEFAULT NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
",
|
||||
PDO_SQL_UPDATE => "
|
||||
--
|
||||
-- Indexes for dumped tables
|
||||
--
|
||||
|
||||
--
|
||||
-- Indexes for table `gaCoolProductRegistrations_prg`
|
||||
--
|
||||
ALTER TABLE `gaCoolProductRegistrations_prg`
|
||||
ADD UNIQUE KEY `whToken_prg` (`whToken_prg`);
|
||||
",
|
||||
/*
|
||||
* example query return:
|
||||
* ---------------------
|
||||
* ALTER TABLE gaTest_tst DROP INDEX gaTest_tst_createdDate_tst_status_tst_index, DROP INDEX
|
||||
* gaTest_tst_lastAccessedDate_tst_index, DROP INDEX testInteger_tst, DROP INDEX
|
||||
* gaTest_tst_eventGuid_tst_index, DROP INDEX testDouble_tst, DROP INDEX testString_tst;
|
||||
*
|
||||
* NOTE:
|
||||
* -----
|
||||
* The sql comment code tag (--) will be removed during mysqlConfig's run time processing
|
||||
*/
|
||||
STRING_DROP_CODE_IDX => "--
|
||||
SELECT CONCAT('ALTER TABLE ', `Table`, ' DROP INDEX ', GROUP_CONCAT(`Index` SEPARATOR ', DROP INDEX '),';' )
|
||||
FROM (
|
||||
SELECT table_name AS `Table`, index_name AS `Index`
|
||||
FROM information_schema.statistics
|
||||
WHERE INDEX_NAME != 'PRIMARY'
|
||||
AND table_schema = 'XXXDROP_DB_NAMEXXX'
|
||||
AND table_name = 'XXXDROP_TABLE_NAMEXXX'
|
||||
GROUP BY `Table`, `Index`) AS tmp
|
||||
GROUP BY `Table`;
|
||||
",
|
||||
STRING_DROP_CODE_DEV => "DROP TABLE IF EXISTS gaCoolProductRegistrations_prg;" // only executed if declared
|
||||
|
||||
]
|
||||
],
|
||||
PDO_VIEWS => [
|
||||
'view_basic_gaWHC1ProductRegistrations' => [
|
||||
STRING_VIEW =>
|
||||
"DROP VIEW IF EXISTS view_basic_gaWHC1ProdRegistrations;
|
||||
CREATE VIEW view_basic_gaWHC1ProdRegistrations_prg AS
|
||||
SELECT type_prg, iid_prg, eav_prg, platform_prg, browser_prg, majorVersion_prg, minorVersion_prg,
|
||||
isMobile_prg, isTablet_prg, firstSeen_prg, lastSeen_prg, eventGUID_prg, createdDate_prg,
|
||||
lastAccessedDate_prg, status_prg, token_prg, whCreated_prg, whEventGuid_prg, whToken_prg
|
||||
FROM gaCoolProductRegistrations_prg;",
|
||||
STRING_TYPE_LIST => null,
|
||||
STRING_DESCRIPTION => 'basic query'
|
||||
],
|
||||
],
|
||||
PDO_PROCEDURES => [],
|
||||
PDO_FUNCTIONS => [],
|
||||
PDO_EVENTS => [],
|
||||
PDO_TRIGGERS => []
|
||||
];
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// MIGRATION DECLARATIONS
|
||||
// ----------------------
|
||||
// Data in this section is used to handle migrations -- when we're pulling from legacy tables into the Namaste
|
||||
// framework. See online doc for more info.
|
||||
//
|
||||
// Note -- this section is not supported for WareHouse templates! (all settings should be null or empty)
|
||||
//=================================================================================================================
|
||||
|
||||
/**
|
||||
* The migration map is an associative array that maps the Namaste fields (keys) to the corresponding
|
||||
* (remote) legacy fields in the source table to be migrated to Namaste.
|
||||
*
|
||||
* For example, if we were migrating a mysql table in the legacy production database to Namaste::mongo, then
|
||||
* the keys of the migration map would be the Namaste::mongo->fieldNames and the values would be the mysql
|
||||
* column names in the legacy table.
|
||||
*
|
||||
* If there is a value which cannot be mapped to a key, then set it to null.
|
||||
*
|
||||
* Fields that will be dropped in the migration are not listed as values or as keys.
|
||||
*
|
||||
* This map will only exist in the template object and will never be imported into the class widget.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationMap = [
|
||||
PDO_ID => null,
|
||||
PRG_TYPE => 'type',
|
||||
PRG_IID => 'iid',
|
||||
PRG_EAV => 'eav',
|
||||
PRG_PLATFORM => 'platform',
|
||||
PRG_BROWSER => 'browser',
|
||||
PRG_MAJOR_VERSION => 'major_version',
|
||||
PRG_MINOR_VERSION => 'minor_version',
|
||||
PRG_IS_MOBILE => 'is_mobile',
|
||||
PRG_IS_TABLET => 'is_tablet',
|
||||
PRG_FIRST_SEEN => 'first_seen',
|
||||
PRG_LAST_SEEN => 'last_seen',
|
||||
DB_TOKEN => null,
|
||||
DB_EVENT_GUID => null, // generated by broker event
|
||||
DB_CREATED => 'kinsert_date', // epoch time
|
||||
DB_STATUS => null, // record status
|
||||
DB_ACCESSED => 'kupdate_date' // epoch time
|
||||
];
|
||||
|
||||
/*
|
||||
* the migrationSortKey defines the SOURCE field by which the fetch query will be sorted. ALL sort fields are
|
||||
* in ASC order so all we need to list here is the name of the field -- which MUST BE IN THE SOURCE TABLE.
|
||||
*
|
||||
* Populating this field may require preliminary examination of the data - what we want is a field that has
|
||||
* zero NULL values.
|
||||
*
|
||||
* This is a required field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationSortKey = null;
|
||||
|
||||
/*
|
||||
* The migrationStatusKey defines the status field/column in the source table -- if the user requires that
|
||||
* soft-deleted records not be migrated, then this field must be set. Otherwise, set the value to null.
|
||||
*
|
||||
* The format is in the form of a key-value paired array. The key specifies the name of the column and the value
|
||||
* specifies the "deleted" value that, if found, will cause that row from the SOURCE data to be omitted from the
|
||||
* DESTINATION table.
|
||||
*
|
||||
* e.g.: $migrationStatusKV = [ 'some_field' => 'deleted' ]
|
||||
*
|
||||
* Note that both the key and the value are case-sensitive!
|
||||
*
|
||||
* This is an optional field.
|
||||
*
|
||||
*/
|
||||
public ?array $migrationStatusKV = null;
|
||||
|
||||
// The $migrationSourceSchema defines the remote schema for the source table
|
||||
public $migrationSourceSchema = ''; // or STRING_MONGO
|
||||
|
||||
// The source table in the remote repos (default defined in the XML) must be declared here
|
||||
public $migrationSourceTable = '';
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS ARE DISABLED FOR WAREHOUSE CLASS OBJECTS
|
||||
// ----------------------------------------------------------------------------------------------------------------
|
||||
public ?array $wareHouse = null;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-23-18 mks CORE-852: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-23-18 mks CORE-852: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 03-23-18 mks CORE-852: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
452
classes/templates/gatWarehouse.class.inc
Normal file
452
classes/templates/gatWarehouse.class.inc
Normal file
@@ -0,0 +1,452 @@
|
||||
<?php
|
||||
/**
|
||||
* gatWarehouse -- mongo admin template class
|
||||
*
|
||||
* gatWarehouse is a data-definition file for warehouse meta data - event data about a data warehousing request that,
|
||||
* during and following a warehouse request event, is stored in the wareHouse collection on the Namaste admin service.
|
||||
*
|
||||
* Again, to be crystal clear, this data class stores (progress, completion) data about the warehouse event - it has
|
||||
* nothing to do with the actual warehousing data other than recording the details about the event request.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 04-12-18 mks _INF-188: original coding (version 1)
|
||||
* 11-04-19 mks DB-136: added DB_EVENT_GUID to $indexFields
|
||||
* 01-14-20 mks DB-150: PHP7.4 class member type-casting
|
||||
* 06-01-20 mks ECI-108: support for auth token
|
||||
*
|
||||
*/
|
||||
|
||||
class gatWarehouse
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_ADMIN; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_CLASS_WAREHOUSE; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_WAREHOUSE; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_MONGO_WAREHOUSE_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = false; // set to true to cache class data
|
||||
public bool $setDeletes = true; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NOT_ENABLED; // set to AUDIT_value constant
|
||||
public bool $setJournaling = false; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = false; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = false; // set to false if the class contains methods
|
||||
public int $cacheTimer = 0; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = true; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you will
|
||||
// need to initialize this member in the constructor (hard-coded)
|
||||
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
MONGO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
MWH_SOURCE_URI => DATA_TYPE_STRING, // URI of the data source, if the source is remote
|
||||
MWH_SOURCE_SCHEMA => DATA_TYPE_STRING, // name of the source schema
|
||||
MWH_SOURCE_TABLE => DATA_TYPE_STRING, // name of the source table
|
||||
MWH_DEST_SCHEMA => DATA_TYPE_STRING, // name of the destination schema
|
||||
MWH_DEST_TABLE => DATA_TYPE_STRING, // name of the destination table
|
||||
MWH_QUERY => DATA_TYPE_STRING, // query used to pull the data from source
|
||||
MWH_QUERY_DATA => DATA_TYPE_STRING, // json-ized string of query parameter data
|
||||
MWH_DATE_STARTED => DATA_TYPE_INTEGER, // when the migration started (epoch time)
|
||||
MWH_NUM_RECS_SOURCE => DATA_TYPE_STRING, // number of records in the source table
|
||||
MWH_NUM_RECS_IN_QUERY => DATA_TYPE_INTEGER, // number of records in the (migration/wh) query
|
||||
MWH_NUM_RECS_MOVED => DATA_TYPE_INTEGER, // number of records migrated
|
||||
MWH_NUM_RECS_DROPPED => DATA_TYPE_INTEGER, // number of records that were dropped
|
||||
MWH_DELETE_TYPE => DATA_TYPE_STRING, // should be hard, soft, or none
|
||||
MWH_LAST_REC_WRITTEN => DATA_TYPE_STRING, // json-encoded string of the last record written
|
||||
MWH_DATE_COMPLETED => DATA_TYPE_INTEGER, // when migration completed (epoch time)
|
||||
MWH_STOP_REASON => DATA_TYPE_STRING, // reason why migration failed
|
||||
MWH_ERROR_CAT => DATA_TYPE_ARRAY, // array of errors
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique key (GUID) exposed externally and is REQUIRED
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER // epoch time
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, MONGO_ID, MWH_SOURCE_SCHEMA, MWH_SOURCE_URI,
|
||||
MWH_SOURCE_TABLE, MIGRATION_DEST_SCHEMA, MIGRATION_DEST_TABLE, MWH_NUM_RECS_SOURCE, MWH_DATE_STARTED
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_CREATED, DB_TOKEN, MWH_SOURCE_TABLE, DB_STATUS,
|
||||
MWH_DEST_TABLE, MWH_DEST_SCHEMA, MWH_SOURCE_SCHEMA, DB_EVENT_GUID
|
||||
];
|
||||
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_CREATED => 1,
|
||||
DB_EVENT_GUID => 1,
|
||||
MWH_SOURCE_TABLE => 1,
|
||||
MWH_DEST_TABLE => 1,
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1 // MONGO_TOKEN should always appear
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null;
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = null;
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
* SubC fields do not need to be indexed.
|
||||
*
|
||||
*/
|
||||
public ?array $subC = null;
|
||||
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_QUALIFIER => null, // query filter for warehousing
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H' // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
];
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 04-12-18 mks _INF-139: original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = NULL_TOKEN;
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 04-12-18 mks _INF-139: original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 04-12-18 mks _INF-139: original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
457
classes/templates/pltDonors.class.inc
Normal file
457
classes/templates/pltDonors.class.inc
Normal file
@@ -0,0 +1,457 @@
|
||||
<?php
|
||||
/** @noinspection PhpUnused */
|
||||
/**
|
||||
* Class pltDonors -- mongo data-template class
|
||||
*
|
||||
* This is the template class for Priceline donors. Priceline fields, as submitted to the SMAX API are defined
|
||||
* as the cache-mapped values s.t. the actual schema remains obfuscated.
|
||||
*
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-12-20 mks ECI-164: original coding
|
||||
*
|
||||
*/
|
||||
|
||||
class pltDonors
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS PROPERTIES...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public int $version = 1; // template version - not the same as the release version
|
||||
public string $service = CONFIG_DATABASE_SERVICE_APPSERVER; // defines the mongo server destination
|
||||
public string $schema = TEMPLATE_DB_MONGO; // defines the storage schema for the class
|
||||
public string $templateClass = TEMPLATE_PL_DONORS; // defines the clear-text template class name
|
||||
public string $collection = COLLECTION_MONGO_PL_DONORS; // sets the collection (table) name
|
||||
public ?string $whTemplate = null; // sets the WH(cool) collection name, null if not wh'd
|
||||
public string $extension = COLLECTION_PL_DONORS_EXT; // sets the extension for the collection
|
||||
public bool $closedClass = true; // set to false to allow partner instantiations
|
||||
public bool $setCache = true; // set to true to cache class data
|
||||
public bool $setDeletes = false; // set to true to allow HARD deletes (otherwise: SOFT)
|
||||
public int $setAuditing = AUDIT_NONDESTRUCTIVE; // set to AUDIT_value constant (nondestructive = reads(yes))
|
||||
public bool $setJournaling = true; // set to true to allow journaling
|
||||
public bool $setUpdates = true; // set to true to allow record updates
|
||||
public bool $setHistory = false; // set to true to enable detailed record history tracking
|
||||
public string $setDefaultStatus = STATUS_ACTIVE; // set the default status for each record
|
||||
public string $setSearchStatus = STATUS_ACTIVE; // set the default search status
|
||||
public bool $setLocking = false; // set to true to enable record locking for collection
|
||||
public bool $setTimers = true; // set to true to enable collection query timers
|
||||
public string $setPKey = DB_TOKEN; // sets the primary key for the collection
|
||||
public bool $setTokens = true; // set to true: adds the idToken field functionality
|
||||
public bool $selfDestruct = true; // set to false if the class contains methods
|
||||
public int $cacheTimer = 300; // number of seconds a tuple will remain in-cache
|
||||
public bool $isGA = false; // set to true is this class is a Namaste internal class
|
||||
public ?string $authToken = null; // if this data class is registered to a partner, you'll
|
||||
// need to initialize this member in the constructor
|
||||
//
|
||||
//
|
||||
// fields: a key-value paired array, defines the field name and the data type for each field. Prior to insertion,
|
||||
// all data is validated for type and membership. Data that does not satisfy these requirements is
|
||||
// silently dropped prior to insertion.
|
||||
public array $fields = [
|
||||
/////// NAMASTE CONSTANTS ////////////////
|
||||
MONGO_ID => DATA_TYPE_INTEGER, // sorting by the id is just like sorting by createdDate
|
||||
DB_TOKEN => DATA_TYPE_STRING, // unique pkey exposed externally and is REQUIRED
|
||||
DB_EVENT_GUID => DATA_TYPE_STRING, // track-back identifier for broker/events
|
||||
DB_CREATED => DATA_TYPE_INTEGER, // epoch time
|
||||
DB_STATUS => DATA_TYPE_STRING, // record status
|
||||
DB_ACCESSED => DATA_TYPE_INTEGER, // epoch time
|
||||
//////////////////////////////////////////
|
||||
PL_CAUSE_TITLE => DATA_TYPE_STRING,
|
||||
PL_CID => DATA_TYPE_STRING,
|
||||
PL_SHARE_DATA_WITH_CAUSE => DATA_TYPE_BOOL,
|
||||
PL_FK => DATA_TYPE_STRING,
|
||||
PL_DONATIONS_TCC => DATA_TYPE_DOUBLE,
|
||||
PL_TOT_DONS => DATA_TYPE_DOUBLE,
|
||||
PL_TRANS_COUNT => DATA_TYPE_INTEGER
|
||||
];
|
||||
|
||||
// protected fields are fields that a client is unable to modify or delete. If a client submits a query that
|
||||
// updates these fields, the query will be rejected (worst case) or the directive to update/delete the field
|
||||
// will be silently dropped (best case). In either way, updating or removing this fields cannot be accomplished.
|
||||
//
|
||||
// Minimally, this array should contain the following fields:
|
||||
// -- DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED
|
||||
// -- the ID field (either PDO_ID or MONGO_ID)
|
||||
// -- DB_WH_CREATED, DB_WH_EVENT_GUID, DB_WH_TOKEN
|
||||
//
|
||||
public ?array $protectedFields = [
|
||||
DB_TOKEN, DB_EVENT_GUID, DB_CREATED, DB_ACCESSED, MONGO_ID
|
||||
];
|
||||
|
||||
// all fields that appear in any of the index declarations must appear in this list as this is the property
|
||||
// that's used in the framework as an authoritative check to qualify discriminant fields as indexes.
|
||||
//
|
||||
// indexes are always declared with the template column name and not the cache-map column name
|
||||
//
|
||||
// warehouse indexes are limited to the original record's created date and the three WH fields only
|
||||
//
|
||||
public array $indexFields = [
|
||||
MONGO_ID, DB_CREATED, DB_STATUS, DB_TOKEN, PL_CID, PL_CAUSE_TITLE, PL_FK
|
||||
];
|
||||
|
||||
// all index names that are explicitly declared in the indexes below must also appear in this array. If there are
|
||||
// no pre-defined index names, then this field should be set to null.
|
||||
//
|
||||
// Note that if you're allowing mysql to generate the index names for you, and if you use a partial index (below)
|
||||
// that references that randomly-generated index name, and that name does not appear in this list, then you will
|
||||
// fail to load that template at run time, every time.
|
||||
//
|
||||
// You have been warned.
|
||||
//
|
||||
public ?array $indexNameList = null;
|
||||
|
||||
// single field index declarations -- since you can have a field in more than one index
|
||||
// (MONGO_ID should NEVER be listed as it's the default single-field index.)
|
||||
// the format for the single-field index declaration is the same format used for all the
|
||||
// index declarations:
|
||||
// [ FIELD_NAME => <SORT-DIRECTION> ] where <SORT_DIR> = [ 1 | -1 ]
|
||||
//
|
||||
// NOTE: if you're going to declare a single column as a property, then do NOT also declare it as a single index!
|
||||
//
|
||||
public ?array $singleFields = [
|
||||
DB_CREATED => -1,
|
||||
PL_CID => 1,
|
||||
PL_CAUSE_TITLE => 1
|
||||
];
|
||||
|
||||
// compound indexes have format of:
|
||||
// [ INDEX-NAME => [ FIELD_NAME => <SORT-DIR>, ... ]]
|
||||
// where INDEX-NAME is a unique string and SORT-DIR = [1|-1]
|
||||
// unless it's for mongoDB -- mongoDB does not use index labels
|
||||
public ?array $compoundIndexes = null;
|
||||
|
||||
// multiKey indexes are indexes on fields that are arrays (not the same as sub-collections) which indexes the
|
||||
// content stored in the array based on the column names.
|
||||
//
|
||||
// mongo, as of 3.4, automatically creates a multi-key index on any field declared as a (sic) index that's
|
||||
// an array. Meaning: we don't need to explicitly create a multi-key index on an array field if that field
|
||||
// is declared as a single-key, compound, or unique index.
|
||||
//
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
// NOTES: if you implicitly declare a multi-key index by using the column as a compound-index field, then you
|
||||
// may, at MOST, have one array within the compound index.
|
||||
//
|
||||
// You may NOT declare a multi-key index as a shard key.
|
||||
//
|
||||
// Hashed keys may NOT be multi-key.
|
||||
// -----------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// In other words, if you want to apply an index to ALL of the array element then declare the column as singleField,
|
||||
// or compound, or unique. This will have the multi-key index automagically applied by mongoDB.
|
||||
//
|
||||
// If you want to index a subset of the array, then declare the fields to be indexed by using dot notation:
|
||||
//
|
||||
// [ 'someIndex' => [ arrayColumnName.subField1 => 1, arrayColumnName.subField3 => -1 ... ] ]
|
||||
//
|
||||
// And this will apply the multi-key index property to subField1 and subField3 only.
|
||||
//
|
||||
// multiKey indexes are referenced by an index name in order to remove ambiguity when parsing index-properties
|
||||
// against this and other indexes that may have the same field name. In other words, index-properties that will
|
||||
// be applied to a multiKey index must reference the multiKey index by the index (and not the column) name.
|
||||
//
|
||||
// example:
|
||||
// [ 'mIdx1Test' => [ ARRAY_FIELD_NAME => <1|-1>, ... ]]
|
||||
//
|
||||
public ?array $multiKey = null;
|
||||
|
||||
/*
|
||||
* Valid index-type constants are:
|
||||
* MONGO_INDEX_TYPE_SINGLE
|
||||
* MONGO_INDEX_TYPE_COMPOUND
|
||||
* MONGO_INDEX_TYPE_MULTIKEY
|
||||
*
|
||||
* INDEXES NOT SUPPORTED BY NAMASTE AT THIS TIME:
|
||||
* ----------------------------------------------
|
||||
* geoSpatial
|
||||
* text
|
||||
* hashed
|
||||
*
|
||||
*/
|
||||
|
||||
// =================================================================================================================
|
||||
// INDEX PROPERTIES
|
||||
// ----------------
|
||||
// Index properties are applied to indexes. The supported properties are:
|
||||
// unique, partial and ttl
|
||||
// sparse is not supported because partial
|
||||
//
|
||||
// If a property is not in-use, then you must still declare the property as a class object but the
|
||||
// value of the property will be set to null.
|
||||
//
|
||||
// Sparse property types are not supported in favor of partials.
|
||||
//
|
||||
// =================================================================================================================
|
||||
|
||||
|
||||
// Partial Indexes are supported as of MongoDB 3.2 and replace sparse indexes. Format for declaration is the
|
||||
// column name as an array key, with the value being a sub-array of a mongo operand and a value, all of which is
|
||||
// associated with either an existing column name or index label.
|
||||
//
|
||||
// If an existing column name is used, then that field must be defined (exists) in one of the above index
|
||||
// declarations for single, compound, or multikey indexes.
|
||||
//
|
||||
// Sparse indexes only add the row to the index if the column referenced satisfies the conditions specified
|
||||
// in the query condition (expr2).
|
||||
//
|
||||
// Format:
|
||||
// { expr1 }, { expr2 }
|
||||
// Where:
|
||||
// expr1 is an indexed column and the index direction. e.g.: { created_tst : 1 }
|
||||
// AND
|
||||
// expr2 is the keyword "partialFilterExpression : { [ query ] }
|
||||
// e.g.: { partialFilterExpression : { integer_tst : { $gte : 10 }}
|
||||
//
|
||||
// db.myTable.createIndex({ lastName: -1, firstName : 1 }, { partialFilterExpression : { age : { $gte : 62 }})
|
||||
// The above index would return a list of names (sorted DESC by last name) for people aged 62 or older.
|
||||
//
|
||||
//
|
||||
public ?array $partialIndexes = null;
|
||||
|
||||
// unique indexes cause MongoDB to reject duplicate values for the indexed field. Unique indexes
|
||||
// are functionally interchangeable with other mongo indexes.
|
||||
// Format:
|
||||
// [ < FIELD_NAME | INDEX-NAME > => <SORT_DIR>, ... ]
|
||||
//
|
||||
public ?array $uniqueIndexes = [
|
||||
DB_TOKEN => 1, // MONGO_TOKEN should always appear
|
||||
PL_FK => 1 // foreign key value should be unique b/c key
|
||||
];
|
||||
|
||||
// ttl indexes contain the column name and the time-to-live in seconds (e.g.: MONGO_TOKEN => 3600)
|
||||
// ttl indexes can only be applied to fields that are MongoDB Date() (object) types, or an array that
|
||||
// contains date values.
|
||||
//
|
||||
// If the field is an array, and there are multiple date values in the index, MongoDB uses lowest
|
||||
// (i.e. earliest) date value in the array to calculate the expiration threshold. If the indexed
|
||||
// field in a document is not a date or an array that holds a date value(s), the document will not expire.
|
||||
//
|
||||
// Format:
|
||||
// [ SOME_FIELD_NAME => ExpireVal ]
|
||||
//
|
||||
// Example:
|
||||
// [ SOME_FIELD_NAME => 86400 ] --- record will be sorted ASC and deleted after 1 day
|
||||
//
|
||||
public ?array $ttlIndexes = null; // ttl indexes appear in $indexFields
|
||||
|
||||
// cache maps are requires for namaste service classes. Even if caching is disabled for a class, a cache map is
|
||||
// still required for the class. For PDO classes, the PDO_ID is never included in the mapping, nor is MONGO_ID.
|
||||
public ?array $cacheMap = [
|
||||
///////// NAMASTE CONSTANTS //////////////
|
||||
DB_TOKEN => CM_TST_TOKEN, //
|
||||
DB_STATUS => CM_TST_FIELD_TEST_STATUS, //
|
||||
DB_EVENT_GUID => CM_TST_EVENT_GUID, //
|
||||
DB_CREATED => CM_TST_FIELD_TEST_CDATE, //
|
||||
DB_ACCESSED => CM_TST_FIELD_TEST_ADATE, //
|
||||
//////////////////////////////////////////
|
||||
PL_CID => PL_CM_CID,
|
||||
PL_CAUSE_TITLE => PL_CM_CAUSE_TITLE,
|
||||
PL_DONATIONS_TCC => PL_CM_DTCC,
|
||||
PL_FK => PL_CM_FK,
|
||||
PL_SHARE_DATA_WITH_CAUSE => PL_CM_SDWC,
|
||||
PL_TOT_DONS => PL_CM_TD,
|
||||
PL_TRANS_COUNT => PL_CM_TC
|
||||
];
|
||||
|
||||
/*
|
||||
* if there is no cache-mapping supported for the class, and you want to limit the fields returned,
|
||||
* then those fields are listed here as an associative array.
|
||||
*
|
||||
* NOTE: You can have caching disabled for the class and still have a cache-map -- this controls the labels
|
||||
* assigned to the returned data column names exposed to the client. Schema should never be exposed.
|
||||
*
|
||||
* NOTE: if you do not support caching for the class and this class is one that is returned to a client,
|
||||
* (some classes are limited to internal use only, like logging), then you should (at a minimum)
|
||||
* exclude the primary key field (integer).
|
||||
*
|
||||
*
|
||||
* This array is an associative array -- the key is the native column name and the value doesn't matter. The
|
||||
* important thing is that the keys are the column names that you want to return back to the client.
|
||||
*
|
||||
* If $exposedFields is to be undefined for the class, then assign it to null.
|
||||
*
|
||||
*/
|
||||
public ?array $exposedFields = null;
|
||||
|
||||
public ?array $binFields = null; // binary fields require special handling; define binary fields here
|
||||
|
||||
// regex fields -- within the indexFields array, which fields enable regex searches?
|
||||
// this does not define an index, but rather to control when to use a regex operand in a query...
|
||||
public ?array $regexFields = null;
|
||||
|
||||
/*
|
||||
* sub-collections represent the implementation of a 1:M relationship at the record-entity level in mongoDB.
|
||||
*
|
||||
* A great example of a sub-collection implementation would be a parent collection called questions and
|
||||
* a sub-collection called answers.
|
||||
*
|
||||
* sub-collections are declared as key->value pairs where each key value is, itself, an array of field names:
|
||||
*
|
||||
* public $subC = [
|
||||
* FIELD_ONE => [
|
||||
* SUB_COLLECTION_FIELD_ONE,
|
||||
* SUB_COLLECTION_FIELD_TWO,
|
||||
* ...
|
||||
* ],
|
||||
* ...
|
||||
* ];
|
||||
*
|
||||
* Each sub-collection field should also appear in both the fields list (to define the types), and in the
|
||||
* cacheMap (if used). If you're not using a cacheMap, and you're limiting the exposed fields, then each
|
||||
* sub-collection field exposed must be listed in the exposed field list. (e.g.: normal rules for exposure
|
||||
* for a collection are applied the same way to a sub-collection.)
|
||||
*
|
||||
* Note that if a sub-Collection key is not listed in either the cacheMap or the exposed field list, then
|
||||
* the entire sub-collection will be invisible to the client. If you list the sub-collection key, you can
|
||||
* limit the sub-collection fields that are exposed by not listing them in either the cacheMap or the
|
||||
* exposed-field lists, respectively.
|
||||
*
|
||||
* Sub-collections are managed within Namaste to allow the sub-collection elements to be either inserted,
|
||||
* or deleted (an update is a delete + insert) without changing the parent field values and, accordingly,
|
||||
* are enabled via discrete class methods.
|
||||
*
|
||||
*/
|
||||
// sub-collection fields must be declared here (need not be indexed)
|
||||
public ?array $subC = null;
|
||||
|
||||
//=================================================================================================================
|
||||
// WAREHOUSE DECLARATIONS
|
||||
// ----------------------
|
||||
// This section handles the warehousing configuration for the class. If a data table is eligible to be ware-
|
||||
// housed, then this section contains all the configuration information, including permissions, for the destination
|
||||
// repository. Note that we need to support bi-directional flow for data.
|
||||
//
|
||||
// Terms/Definitions:
|
||||
// ------------------
|
||||
// HOT -- data is in production
|
||||
// COOL -- data has been warehoused, maintains schema, but with indexing changes.
|
||||
// COLD -- data has been warehoused but formatted to the destination schema, usually CSV.
|
||||
// WARM -- indicates any data moving from COLD -> HOT
|
||||
//
|
||||
// Design Features:
|
||||
// ----------------
|
||||
// Supported
|
||||
// This is a boolean value that indicates if the class supports warehousing. If this is set to false, then
|
||||
// warehousing requests for the class will be rejected.
|
||||
//
|
||||
// Remote Support
|
||||
// --------------
|
||||
// This is a boolean value that indicates if the class will support a warehouse source outside of the Namaste
|
||||
// framework. If this is set to false, and a user submits a request defining the data source as a remote
|
||||
// repository, the request will be rejected.
|
||||
//
|
||||
// Automated
|
||||
// This is a boolean value that indicates if the class allows automated warehousing, meaning that data will be
|
||||
// warehoused once the qualifying condition has been met.
|
||||
//
|
||||
// Dynamic
|
||||
// Boolean value that, if set to true, indicates that the class will accept dynamic requests. Otherwise, the
|
||||
// warehousing operations will follow the interval schedule. Defaults to false.
|
||||
//
|
||||
// Interval
|
||||
// This is a string value that tells the AT_micro-service how often to run automated warehousing on the data.
|
||||
// D = Daily, M = 1st of every month, Q = 1st of every quarter, Y = 1st of every year
|
||||
// The default setting for this value should be monthly (M).
|
||||
//
|
||||
// Qualifier
|
||||
// This is a query string, similar to what you would provide to Namaste for a fetch operation, that establishes
|
||||
// the filter/criteria for moving data to the warehouse. If Supported is set to true, this cannot be blank.
|
||||
//
|
||||
// Override
|
||||
// Boolean value indicating if, and only for dynamic event requests, if the Qualifier can be overridden. If
|
||||
// set to true, the the event request must contain a valid query filter.
|
||||
//
|
||||
// Delete
|
||||
// This is a string value that tells Namaste what to do with the source data once successfully warehoused.
|
||||
// H = hard delete, S = soft delete
|
||||
// Note that this value overrides the $setDeletes setting.
|
||||
//
|
||||
//=================================================================================================================
|
||||
|
||||
public ?array $wareHouse = [
|
||||
WH_SUPPORTED => false, // must be set to true for data class to support any warehousing
|
||||
WH_REMOTE_SUPPORT => false, // must be set to true to import data into this class from remote source
|
||||
WH_AUTOMATED => false, // must be set to true for warehousing to be automatically processed
|
||||
WH_DYNAMIC => false, // must be set to true to allow non-scheduled event requests
|
||||
WH_INTERVAL => 'M', // must be either D, M, Q or A, defaults to M
|
||||
WH_OVERRIDE => false, // must be set to true to allow an ad-hoc query filter
|
||||
WH_DELETE => 'H', // must be either H, or S. Can be reset to T via meta. Default: H
|
||||
|
||||
// default warehouse query to grab records where the date is LT a value and the status is active:
|
||||
// the null value will be replaced with the value provided by the client in the wh request payload.
|
||||
WH_QUALIFIER => [
|
||||
DB_CREATED => [OPERAND_NULL => [OPERATOR_LT => [null]]],
|
||||
DB_STATUS => [OPERAND_NULL => [OPERATOR_EQ => [STATUS_ACTIVE]]],
|
||||
OPERAND_AND => null
|
||||
]
|
||||
];
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CLASS METHODS...
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* __construct() -- public method
|
||||
*
|
||||
* we have a constructor to register the destructor.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-12-20 mks ECI-164: Original coding
|
||||
*
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->authToken = '136EA67A-B1E2-0A4B-2BD8-EE34D39DFDE1'; // make sure this exists in the SMAX_API collection
|
||||
register_shutdown_function([$this, STRING_DESTRUCTOR]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __clone() -- private function
|
||||
*
|
||||
* Silently disallows cloning of the object
|
||||
*
|
||||
* @return null
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-12-20 mks ECI-164: Original coding
|
||||
*
|
||||
*/
|
||||
private function __clone()
|
||||
{
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* __destruct() -- public function
|
||||
*
|
||||
* As of PHP 5.3.10 destructors are not run on shutdown caused by fatal errors.
|
||||
*
|
||||
* The destructor is registered as a shut-down function in the constructor -- so any recovery
|
||||
* efforts should go in this method.
|
||||
*
|
||||
* @author mike@givingassistant.org
|
||||
* @version 1.0
|
||||
*
|
||||
* HISTORY:
|
||||
* ========
|
||||
* 06-12-20 mks ECI-164: Original coding
|
||||
*
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
// empty method
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user