DB\IO: add convert types to php type (TTD-606)
Convert DB types to PHP types Current settings: - off - on: int/bool on;y - json: json strings to array - numeric: and real/float to php float (possible precision loss) - bytea: convert PostgreSQL bytea strings to php data strings
This commit is contained in:
@@ -41,7 +41,8 @@ class EditBase
|
||||
/**
|
||||
* construct form generator
|
||||
*
|
||||
* @param array<mixed> $db_config db config array, mandatory
|
||||
* phpcs:ignore
|
||||
* @param array{db_name:string,db_user:string,db_pass:string,db_host:string,db_port:int,db_schema:string,db_encoding:string,db_type:string,db_ssl:string,db_convert_type?:string[]} $db_config db config array, mandatory
|
||||
* @param \CoreLibs\Logging\Logging $log Logging class, null auto set
|
||||
* @param \CoreLibs\Language\L10n $l10n l10n language class, null auto set
|
||||
* @param \CoreLibs\ACL\Login $login login class for ACL settings
|
||||
|
||||
@@ -54,7 +54,8 @@ class ArrayIO extends \CoreLibs\DB\IO
|
||||
* constructor for the array io class, set the
|
||||
* primary key name automatically (from array)
|
||||
*
|
||||
* @param array<mixed> $db_config db connection config
|
||||
* phpcs:ignore
|
||||
* @param array{db_name:string,db_user:string,db_pass:string,db_host:string,db_port:int,db_schema:string,db_encoding:string,db_type:string,db_ssl:string,db_convert_type?:string[]} $db_config db connection config
|
||||
* @param array<mixed> $table_array table array config
|
||||
* @param string $table_name table name string
|
||||
* @param \CoreLibs\Logging\Logging $log Logging class
|
||||
|
||||
379
src/DB/IO.php
379
src/DB/IO.php
@@ -259,6 +259,8 @@ namespace CoreLibs\DB;
|
||||
use CoreLibs\Create\Hash;
|
||||
use CoreLibs\Debug\Support;
|
||||
use CoreLibs\Create\Uids;
|
||||
use CoreLibs\Convert\Json;
|
||||
use CoreLibs\DB\Options\Convert;
|
||||
|
||||
// below no ignore is needed if we want to use PgSql interface checks with PHP 8.0
|
||||
// as main system. Currently all @var sets are written as object
|
||||
@@ -328,6 +330,17 @@ class IO
|
||||
private string $db_type;
|
||||
/** @var string ssl flag (for postgres only), disable, allow, prefer, require */
|
||||
private string $db_ssl;
|
||||
/** @var array<string> flag for converting types from settings */
|
||||
private array $db_convert_type = [];
|
||||
// convert type settings
|
||||
// 0: OFF (CONVERT_OFF)
|
||||
// >0: ON
|
||||
// 1: convert intN/bool (CONVERT_ON)
|
||||
// 2: convert json/jsonb to array (CONVERT_JSON)
|
||||
// 4: convert numeric/floatN to float (CONVERT_NUMERIC)
|
||||
// 8: convert bytea to string data (CONVERT_BYTEA)
|
||||
/** @var int type settings as bit mask, 0 for off, anything >2 will aways set 1 too */
|
||||
private int $convert_type = Convert::off->value;
|
||||
// FOR BELOW: (This should be private and only readable through some method)
|
||||
// cursor array for cached readings
|
||||
/** @var array<string,mixed> extended cursoers string index with content */
|
||||
@@ -343,6 +356,8 @@ class IO
|
||||
private array $field_names = [];
|
||||
/** @var array<string> field type names */
|
||||
private array $field_types = [];
|
||||
/** @var array<string,string> field name to type */
|
||||
private array $field_name_types = [];
|
||||
/** @var array<mixed> always return as array, even if only one */
|
||||
private array $insert_id_arr = [];
|
||||
/** @var string primary key name for insert recovery from insert_id_arr */
|
||||
@@ -392,8 +407,11 @@ class IO
|
||||
public \CoreLibs\Logging\Logging $log;
|
||||
|
||||
/**
|
||||
* main DB concstructor with auto connection to DB and failure set on failed connection
|
||||
* @param array<mixed> $db_config DB configuration array
|
||||
* main DB concstructor with auto connection to DB
|
||||
* and failure set on failed connection
|
||||
*
|
||||
* phpcs:ignore
|
||||
* @param array{db_name:string,db_user:string,db_pass:string,db_host:string,db_port:int,db_schema:string,db_encoding:string,db_type:string,db_ssl:string,db_convert_type?:string[]} $db_config DB configuration array
|
||||
* @param \CoreLibs\Logging\Logging $log Logging class
|
||||
*/
|
||||
public function __construct(
|
||||
@@ -402,17 +420,8 @@ class IO
|
||||
) {
|
||||
// attach logger
|
||||
$this->log = $log;
|
||||
// sets the names (for connect/reconnect)
|
||||
$this->db_name = $db_config['db_name'] ?? '';
|
||||
$this->db_user = $db_config['db_user'] ?? '';
|
||||
$this->db_pwd = $db_config['db_pass'] ?? '';
|
||||
$this->db_host = $db_config['db_host'] ?? '';
|
||||
$this->db_port = !empty($db_config['db_port']) ? (int)$db_config['db_port'] : 5432;
|
||||
// do not set to 'public' if not set, because the default is already public
|
||||
$this->db_schema = !empty($db_config['db_schema']) ? $db_config['db_schema'] : '';
|
||||
$this->db_encoding = !empty($db_config['db_encoding']) ? $db_config['db_encoding'] : '';
|
||||
$this->db_type = $db_config['db_type'] ?? '';
|
||||
$this->db_ssl = !empty($db_config['db_ssl']) ? $db_config['db_ssl'] : 'allow';
|
||||
// set the config options
|
||||
$this->__setConfigOptions($db_config);
|
||||
// set debug, either via global var, or from config, else set to false
|
||||
$this->dbSetDebug(
|
||||
// set if logging level is Debug
|
||||
@@ -497,6 +506,84 @@ class IO
|
||||
// PRIVATE METHODS
|
||||
// *************************************************************
|
||||
|
||||
/**
|
||||
* Setup DB config and options
|
||||
*
|
||||
* phpcs:ignore
|
||||
* @param array{db_name:string,db_user:string,db_pass:string,db_host:string,db_port:int,db_schema:string,db_encoding:string,db_type:string,db_ssl:string,db_convert_type?:string[]} $db_config
|
||||
* @return bool
|
||||
*/
|
||||
private function __setConfigOptions(array $db_config): bool
|
||||
{
|
||||
// sets the names (for connect/reconnect)
|
||||
$this->db_name = $db_config['db_name'] ?? '';
|
||||
$this->db_user = $db_config['db_user'] ?? '';
|
||||
$this->db_pwd = $db_config['db_pass'] ?? '';
|
||||
$this->db_host = $db_config['db_host'] ?? '';
|
||||
// port
|
||||
$this->db_port = !empty($db_config['db_port']) ?
|
||||
(int)$db_config['db_port'] : 5432;
|
||||
if ($this->db_port < 0 || $this->db_port > 65535) {
|
||||
$this->db_port = 5432;
|
||||
}
|
||||
// do not set to 'public' if not set, because the default is already public
|
||||
$this->db_schema = !empty($db_config['db_schema']) ?
|
||||
$db_config['db_schema'] : '';
|
||||
$this->db_encoding = !empty($db_config['db_encoding']) ?
|
||||
$db_config['db_encoding'] : '';
|
||||
// db type
|
||||
$this->db_type = $db_config['db_type'] ?? '';
|
||||
if (!in_array($this->db_type, ['pgsql'])) {
|
||||
$this->db_type = 'pgsql';
|
||||
}
|
||||
// ssl setting
|
||||
$this->db_ssl = !empty($db_config['db_ssl']) ?
|
||||
$db_config['db_ssl'] : 'allow';
|
||||
if (!in_array($this->db_ssl, ['allow', 'disable', 'require', 'prefer'])) {
|
||||
$this->db_ssl = 'allow';
|
||||
}
|
||||
// trigger convert type
|
||||
// ['on', 'json', 'numeric', 'bytea'] allowed
|
||||
// if on is not set but other valid than on is assumed
|
||||
foreach ($db_config['db_convert_type'] ?? [] as $db_convert_type) {
|
||||
if (!in_array($db_convert_type, ['on', 'json', 'numeric', 'bytea'])) {
|
||||
continue;
|
||||
}
|
||||
$this->db_convert_type[] = $db_convert_type;
|
||||
$this->__setConvertType($db_convert_type);
|
||||
}
|
||||
|
||||
// return status true: ok, false: options error
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the convert bit flags
|
||||
*
|
||||
* @param string $db_convert_type One of 'on', 'json', 'numeric', 'bytea'
|
||||
* @return void
|
||||
*/
|
||||
private function __setConvertType(string $db_convert_type): void
|
||||
{
|
||||
switch ($db_convert_type) {
|
||||
case 'on':
|
||||
$this->convert_type |= Convert::on->value;
|
||||
break;
|
||||
case 'json':
|
||||
$this->convert_type |= Convert::on->value;
|
||||
$this->convert_type |= Convert::json->value;
|
||||
break;
|
||||
case 'numeric':
|
||||
$this->convert_type |= Convert::on->value;
|
||||
$this->convert_type |= Convert::numeric->value;
|
||||
break;
|
||||
case 'bytea':
|
||||
$this->convert_type |= Convert::on->value;
|
||||
$this->convert_type |= Convert::bytea->value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* based on $this->db_type
|
||||
* here we need to load the db pgsql include one
|
||||
@@ -525,8 +612,10 @@ class IO
|
||||
}
|
||||
|
||||
/**
|
||||
* internal connection function. Used to connect to the DB if there is no connection done yet.
|
||||
* internal connection function.
|
||||
* Used to connect to the DB if there is no connection done yet.
|
||||
* Called before any execute
|
||||
*
|
||||
* @return bool true on successfull connect, false if failed
|
||||
*/
|
||||
private function __connectToDB(): bool
|
||||
@@ -571,6 +660,7 @@ class IO
|
||||
/**
|
||||
* close db connection
|
||||
* only used by the deconstructor
|
||||
*
|
||||
* @return void has no return
|
||||
*/
|
||||
private function __closeDB(): void
|
||||
@@ -585,6 +675,7 @@ class IO
|
||||
* checks if query is a SELECT, SHOW or WITH, if not error, 0 return
|
||||
* NOTE:
|
||||
* Query needs to start with SELECT, SHOW or WITH
|
||||
*
|
||||
* @param string $query query to check
|
||||
* @return bool true if matching, false if not
|
||||
*/
|
||||
@@ -602,6 +693,7 @@ class IO
|
||||
* if pure is set to true, only when INSERT is set will return true
|
||||
* NOTE:
|
||||
* Queries need to start with INSERT, UPDATE, DELETE. Anything else is ignored
|
||||
*
|
||||
* @param string $query query to check
|
||||
* @param bool $pure pure check (only insert), default false
|
||||
* @return bool true if matching, false if not
|
||||
@@ -620,6 +712,7 @@ class IO
|
||||
/**
|
||||
* returns true if the query starts with UPDATE
|
||||
* query NEEDS to start with UPDATE
|
||||
*
|
||||
* @param string $query query to check
|
||||
* @return bool returns true if the query starts with UPDATE
|
||||
*/
|
||||
@@ -635,6 +728,7 @@ class IO
|
||||
* internal funktion that creates the array
|
||||
* NOTE:
|
||||
* used in db_dump_data only
|
||||
*
|
||||
* @param array<mixed> $array array to print
|
||||
* @return string string with printed and formated array
|
||||
*/
|
||||
@@ -706,7 +800,12 @@ class IO
|
||||
$this->log->warning($debug_id . ' :' . $prefix . $error_string);
|
||||
break;
|
||||
default:
|
||||
$this->log->debug($debug_id, $error_string, $prefix);
|
||||
// used named arguments so we can easy change the order of debug
|
||||
$this->log->debug(
|
||||
group_id: $debug_id,
|
||||
message: $error_string,
|
||||
prefix: $prefix
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -740,6 +839,7 @@ class IO
|
||||
* Is called on base queries to reset error before each run
|
||||
* Recent error history can be checked with
|
||||
* dbGetErrorHistory or dbGetWarningHistory
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function __dbErrorReset(): void
|
||||
@@ -751,6 +851,7 @@ class IO
|
||||
|
||||
/**
|
||||
* Check if there is a cursor and write this cursors error info
|
||||
*
|
||||
* @param \PgSql\Result|false $cursor current cursor for pg_result_error,
|
||||
* pg_last_error too, but pg_result_error
|
||||
* is more accurate (PgSql\Result)
|
||||
@@ -811,6 +912,7 @@ class IO
|
||||
* error level, source as :: separated string
|
||||
* additional pg error message if exists and optional msg given on error call
|
||||
* all error messages are grouped by error_history_id set when errors are reset
|
||||
*
|
||||
* @param string $level
|
||||
* @param string $error_id
|
||||
* @param string $where_called
|
||||
@@ -841,6 +943,7 @@ class IO
|
||||
|
||||
/**
|
||||
* write an error
|
||||
*
|
||||
* @param integer $error_id Any Error ID, used in debug message string
|
||||
* @param \PgSql\Result|false $cursor Optional cursor, passed on to preprocessor
|
||||
* @param string $msg optional message added to debug
|
||||
@@ -868,6 +971,7 @@ class IO
|
||||
|
||||
/**
|
||||
* write a warning
|
||||
*
|
||||
* @param integer $warning_id Integer warning id added to debug
|
||||
* @param \PgSql\Result|false $cursor Optional cursor, passed on to preprocessor
|
||||
* @param string $msg optional message added to debug
|
||||
@@ -895,6 +999,7 @@ class IO
|
||||
/**
|
||||
* if there is the 'to_encoding' var set,
|
||||
* and the field is in the wrong encoding converts it to the target
|
||||
*
|
||||
* @param array<mixed>|false $row Array from fetch_row
|
||||
* @return array<mixed>|false Convert fetch_row array, or false
|
||||
*/
|
||||
@@ -903,11 +1008,8 @@ class IO
|
||||
if (is_bool($row)) {
|
||||
return false;
|
||||
}
|
||||
// only do if array, else pass through row (can be false)
|
||||
if (
|
||||
!is_array($row) ||
|
||||
empty($this->to_encoding)
|
||||
) {
|
||||
// do not do anything if no to encoding is set
|
||||
if (empty($this->to_encoding)) {
|
||||
return $row;
|
||||
}
|
||||
// go through each row and convert the encoding if needed
|
||||
@@ -929,8 +1031,70 @@ class IO
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert column content to the type in the name/pos field
|
||||
* Note that on default it will only convert types that 100% map to PHP
|
||||
* - intN
|
||||
* - bool
|
||||
* everything else will stay string.
|
||||
* Fruther flags in the conert_type allow to convert:
|
||||
* - json/jsonb to array
|
||||
* - bytea to string
|
||||
* Dangerous convert:
|
||||
* - numeric/float to float (precision can be lost)
|
||||
*
|
||||
* @param array<mixed>|false $row
|
||||
* @return array<mixed>|false
|
||||
*/
|
||||
private function __dbConvertType(array|false $row): array|false
|
||||
{
|
||||
if (is_bool($row)) {
|
||||
return false;
|
||||
}
|
||||
// if convert type is not turned on
|
||||
if (!$this->convert_type) {
|
||||
return $row;
|
||||
}
|
||||
foreach ($row as $key => $value) {
|
||||
// always bool/int
|
||||
if (
|
||||
$this->dbGetFieldType($key) != 'interval' &&
|
||||
str_starts_with($this->dbGetFieldType($key) ?: '', 'int')
|
||||
) {
|
||||
$row[$key] = (int)$value;
|
||||
}
|
||||
if ($this->dbGetFieldType($key) == 'bool') {
|
||||
$row[$key] = $this->dbBoolean($value);
|
||||
}
|
||||
if (
|
||||
$this->convert_type & Convert::json->value &&
|
||||
str_starts_with($this->dbGetFieldType($key) ?: '', 'json')
|
||||
) {
|
||||
$row[$key] = Json::jsonConvertToArray($value);
|
||||
}
|
||||
if (
|
||||
$this->convert_type & Convert::numeric->value &&
|
||||
(
|
||||
str_starts_with($this->dbGetFieldType($key) ?: '', 'numeric') ||
|
||||
str_starts_with($this->dbGetFieldType($key) ?: '', 'float')
|
||||
// $this->dbGetFieldType($key) == 'real'
|
||||
)
|
||||
) {
|
||||
$row[$key] = (float)$value;
|
||||
}
|
||||
if (
|
||||
$this->convert_type & Convert::bytea->value &&
|
||||
$this->dbGetFieldType($key) == 'bytea'
|
||||
) {
|
||||
$row[$key] = $this->dbUnescapeBytea($value);
|
||||
}
|
||||
}
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* for debug purpose replaces $1, $2, etc with actual data
|
||||
*
|
||||
* @param string $query Query to replace values in
|
||||
* @param array<mixed> $data The data array
|
||||
* @return string string of query with data inside
|
||||
@@ -964,7 +1128,9 @@ class IO
|
||||
}
|
||||
|
||||
/**
|
||||
* extracts schema and table from the query, if no schema returns just empty string
|
||||
* extracts schema and table from the query,
|
||||
* if no schema returns just empty string
|
||||
*
|
||||
* @param string $query insert/select/update/delete query
|
||||
* @return array<mixed> array with schema and table
|
||||
*/
|
||||
@@ -1003,6 +1169,7 @@ class IO
|
||||
/**
|
||||
* check if there is another query running, or do we hang after a
|
||||
* PHP error
|
||||
*
|
||||
* @param integer $timeout_seconds For complex timeout waits, default 3 seconds
|
||||
* @return bool True for connection OK, else false
|
||||
*/
|
||||
@@ -1021,6 +1188,7 @@ class IO
|
||||
/**
|
||||
* dbReturn
|
||||
* Read data from previous written data cache
|
||||
*
|
||||
* @param string $query_hash The hash for the current query
|
||||
* @param bool $assoc_only Only return assoc value (key named)
|
||||
* @return array<mixed> Current position query data from cache
|
||||
@@ -1099,6 +1267,7 @@ class IO
|
||||
* - checks for insert if returning is set/pk name
|
||||
* - sets internal hash for query
|
||||
* - checks multiple call count
|
||||
*
|
||||
* @param string $query Query string
|
||||
* @param array<mixed> $params Query params, needed for hash creation
|
||||
* @param string $pk_name primary key
|
||||
@@ -1183,7 +1352,7 @@ class IO
|
||||
) {
|
||||
$this->returning_id = true;
|
||||
}
|
||||
// $this->debug('DB IO', 'Q: '.$this->query.', RETURN: '.$this->returning_id);
|
||||
// $this->debug('DB IO', 'Q: ' . $this->query . ', RETURN: ' . $this->returning_id);
|
||||
// for DEBUG, only on first time ;)
|
||||
$this->__dbDebug(
|
||||
'db',
|
||||
@@ -1229,6 +1398,7 @@ class IO
|
||||
|
||||
/**
|
||||
* runs post execute for rows affected, field names, inserted primary key, etc
|
||||
*
|
||||
* @return bool true on success or false if an error occured
|
||||
*/
|
||||
private function __dbPostExec(): bool
|
||||
@@ -1254,11 +1424,18 @@ class IO
|
||||
$this->field_names = [];
|
||||
for ($i = 0; $i < $this->num_fields; $i++) {
|
||||
$this->field_names[] = $this->db_functions->__dbFieldName($this->cursor, $i) ?: '';
|
||||
// if (!empty($this->field_names[$i]))
|
||||
// $this->field_name_types[$this->field_names[$i]] = null;
|
||||
}
|
||||
$this->field_types = [];
|
||||
for ($i = 0; $i < $this->num_fields; $i++) {
|
||||
$this->field_types[] = $this->db_functions->__dbFieldType($this->cursor, $i) ?: '';
|
||||
}
|
||||
// combined array
|
||||
$this->field_name_types = array_combine(
|
||||
$this->field_names,
|
||||
$this->field_types
|
||||
);
|
||||
} elseif ($this->__checkQueryForInsert($this->query)) {
|
||||
// if not select do here
|
||||
// count affected rows
|
||||
@@ -1292,6 +1469,7 @@ class IO
|
||||
* insert_id_ext [DEPRECATED, all in insert_id_arr]
|
||||
* - holds all returning as array
|
||||
* TODO: Only use insert_id_arr and use functions to get ok array or single
|
||||
*
|
||||
* @param bool $returning_id
|
||||
* @param string $query
|
||||
* @param string|null $pk_name
|
||||
@@ -1384,6 +1562,7 @@ class IO
|
||||
* closes the db_connection
|
||||
* normally this is not used, as the class deconstructor closes
|
||||
* the connection down
|
||||
*
|
||||
* @return void has no return
|
||||
*/
|
||||
public function dbClose(): void
|
||||
@@ -1405,6 +1584,7 @@ class IO
|
||||
* returns the db init error
|
||||
* if failed to connect it is set to false
|
||||
* else true
|
||||
*
|
||||
* @return bool Connection status
|
||||
*/
|
||||
public function dbGetConnectionStatus(): bool
|
||||
@@ -1414,6 +1594,7 @@ class IO
|
||||
|
||||
/**
|
||||
* get certain settings like username, db name
|
||||
*
|
||||
* @param string $name what setting to query
|
||||
* @return int|string|bool setting value, if not allowed name return false
|
||||
*/
|
||||
@@ -1458,6 +1639,7 @@ class IO
|
||||
|
||||
/**
|
||||
* prints out status info from the connected DB (might be usefull for debug stuff)
|
||||
*
|
||||
* @param bool $log Show db connection info, default true
|
||||
* if set to false won't write to error_msg var
|
||||
* @param bool $strip Strip all HTML
|
||||
@@ -1497,6 +1679,7 @@ class IO
|
||||
|
||||
/**
|
||||
* Server version as integer value
|
||||
*
|
||||
* @return integer Version as integer
|
||||
*/
|
||||
public function dbVersionNumeric(): int
|
||||
@@ -1506,6 +1689,7 @@ class IO
|
||||
|
||||
/**
|
||||
* return current database version (server side) as string
|
||||
*
|
||||
* @return string database version as string
|
||||
*/
|
||||
public function dbVersion(): string
|
||||
@@ -1515,6 +1699,7 @@ class IO
|
||||
|
||||
/**
|
||||
* extended version info, can access all additional information data
|
||||
*
|
||||
* @param string $parameter Array parameter name, if not valid returns
|
||||
* empty string
|
||||
* @param bool $strip Strip extended server info string, default true
|
||||
@@ -1528,6 +1713,7 @@ class IO
|
||||
|
||||
/**
|
||||
* All possible parameter names for dbVersionInfo
|
||||
*
|
||||
* @return array<mixed> List of all parameter names
|
||||
*/
|
||||
public function dbVersionInfoParameters(): array
|
||||
@@ -1537,6 +1723,7 @@ class IO
|
||||
|
||||
/**
|
||||
* returns bool true or false if the string matches the database version
|
||||
*
|
||||
* @param string $compare string to match in type =X.Y, >X.Y, <X.Y, <=X.Y, >=X.Y
|
||||
* @return bool true for ok, false on not ok
|
||||
*/
|
||||
@@ -1605,6 +1792,7 @@ class IO
|
||||
|
||||
/**
|
||||
* dumps ALL data for this query, OR if no query given all in cursor_ext array
|
||||
*
|
||||
* @param string $query Query, if given, only from this quey (if found)
|
||||
* else current cursor
|
||||
* @return string Formated string with all the data in the array
|
||||
@@ -1632,6 +1820,7 @@ class IO
|
||||
|
||||
/**
|
||||
* neutral function to escape a string for DB writing
|
||||
*
|
||||
* @param string|int|float|bool $string string to escape
|
||||
* @return string escaped string
|
||||
*/
|
||||
@@ -1643,6 +1832,7 @@ class IO
|
||||
/**
|
||||
* neutral function to escape a string for DB writing
|
||||
* this one adds '' quotes around the string
|
||||
*
|
||||
* @param string|int|float|bool $string string to escape
|
||||
* @return string escaped string
|
||||
*/
|
||||
@@ -1653,6 +1843,7 @@ class IO
|
||||
|
||||
/**
|
||||
* string escape for column and table names
|
||||
*
|
||||
* @param string $string string to escape
|
||||
* @return string escaped string
|
||||
*/
|
||||
@@ -1663,6 +1854,7 @@ class IO
|
||||
|
||||
/**
|
||||
* escape data for writing to bytea type column field
|
||||
*
|
||||
* @param string $data data to escape to bytea
|
||||
* @return string escaped bytea string
|
||||
*/
|
||||
@@ -1673,6 +1865,7 @@ class IO
|
||||
|
||||
/**
|
||||
* unescape bytea data back to normal binrary data
|
||||
*
|
||||
* @param string $bytea bytea data stream
|
||||
* @return string binary data string
|
||||
*/
|
||||
@@ -1683,6 +1876,7 @@ class IO
|
||||
|
||||
/**
|
||||
* clear up any data for valid DB insert
|
||||
*
|
||||
* @param int|float|string|bool|null $value to escape data
|
||||
* @param string $kbn escape trigger type
|
||||
* @return string escaped value
|
||||
@@ -1749,10 +1943,11 @@ class IO
|
||||
* if the input is a single char 't' or 'f
|
||||
* it will return the bool value instead
|
||||
* also converts smallint 1/0 to true false
|
||||
*
|
||||
* @param string|bool|int $string 't' / 'f' or any string, or bool true/false
|
||||
* @param bool $rev do reverse (bool to string)
|
||||
* @return bool|string correct php bool true/false
|
||||
* or postgresql 't'/'f'
|
||||
* @return bool|string [default=false]: corretc postgresql -> php,
|
||||
* true: convert php to postgresql
|
||||
*/
|
||||
public function dbBoolean(string|bool|int $string, bool $rev = false): bool|string
|
||||
{
|
||||
@@ -1784,6 +1979,7 @@ class IO
|
||||
|
||||
/**
|
||||
* only for postgres. pretty formats an age or datetime difference string
|
||||
*
|
||||
* @param string $interval Age or interval/datetime difference
|
||||
* @param bool $show_micro micro on off (default false)
|
||||
* @return string Y/M/D/h/m/s formatted string (like timeStringFormat)
|
||||
@@ -1835,6 +2031,7 @@ class IO
|
||||
/**
|
||||
* this is only needed for Postgresql. Converts postgresql arrays to PHP
|
||||
* Recommended to rather user 'array_to_json' instead and convet JSON in PHP
|
||||
*
|
||||
* @param string $text input text to parse to an array
|
||||
* @return array<mixed> PHP array of the parsed data
|
||||
* @deprecated Recommended to use 'array_to_json' in PostgreSQL instead
|
||||
@@ -1851,6 +2048,7 @@ class IO
|
||||
|
||||
/**
|
||||
* returns an array of the table with columns and values. FALSE on no table found
|
||||
*
|
||||
* @param string $table table name
|
||||
* @param string $schema optional schema name
|
||||
* @return array<mixed>|false array of table data, false on error (table not found)
|
||||
@@ -1954,6 +2152,10 @@ class IO
|
||||
'data' => [],
|
||||
// field names as array
|
||||
'field_names' => [],
|
||||
// field types as array (pos in field names is pos here)
|
||||
'field_types' => [],
|
||||
// name to type assoc array (from field names and field types)
|
||||
'field_name_types' => [],
|
||||
// number of fields (field names)
|
||||
'num_fields' => 0,
|
||||
// number of rows that will be maximum returned
|
||||
@@ -2117,6 +2319,12 @@ class IO
|
||||
);
|
||||
}
|
||||
$this->field_types = $this->cursor_ext[$query_hash]['field_types'];
|
||||
// combined name => type
|
||||
$this->cursor_ext[$query_hash]['field_name_types'] = array_combine(
|
||||
$this->field_names,
|
||||
$this->field_types
|
||||
);
|
||||
$this->field_name_types = $this->cursor_ext[$query_hash]['field_name_types'];
|
||||
// reset first call var
|
||||
$first_call = false;
|
||||
// reset the internal pos counter
|
||||
@@ -2139,10 +2347,12 @@ class IO
|
||||
!is_int($this->cursor_ext[$query_hash]['cursor'])
|
||||
) {
|
||||
$return = $this->__dbConvertEncoding(
|
||||
$this->__dbConvertType(
|
||||
$this->db_functions->__dbFetchArray(
|
||||
$this->cursor_ext[$query_hash]['cursor'],
|
||||
$this->db_functions->__dbResultType($assoc_only)
|
||||
)
|
||||
)
|
||||
);
|
||||
$this->cursor_ext[$query_hash]['log'][] = 'DB Reading data: '
|
||||
. (is_bool($return) ? 'EOF' : 'DATA');
|
||||
@@ -2238,6 +2448,7 @@ class IO
|
||||
* for INSERT INTO queries it is highly recommended to set the pk_name to avoid an
|
||||
* additional read from the database for the PK NAME
|
||||
* Wrapper for dbExecParams without params
|
||||
*
|
||||
* @param string $query the query, if not given,
|
||||
* the query class var will be used
|
||||
* if this was not set, method will quit with false
|
||||
@@ -2307,10 +2518,9 @@ class IO
|
||||
}
|
||||
}
|
||||
|
||||
// add adbExecParams(string $query = '', array $params = [], string $pk_name = ')
|
||||
|
||||
/**
|
||||
* executes a cursor and returns the data, if no more data 0 will be returned
|
||||
*
|
||||
* @param \PgSql\Result|false $cursor the cursor from db_exec or
|
||||
* pg_query/pg_exec/mysql_query
|
||||
* if not set will use internal cursor,
|
||||
@@ -2333,16 +2543,19 @@ class IO
|
||||
return false;
|
||||
}
|
||||
return $this->__dbConvertEncoding(
|
||||
$this->__dbConvertType(
|
||||
$this->db_functions->__dbFetchArray(
|
||||
$cursor,
|
||||
$this->db_functions->__dbResultType($assoc_only)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the FIRST row of the given query
|
||||
* wrapper for dbReturnRowParms
|
||||
*
|
||||
* @param string $query the query to be executed
|
||||
* @param bool $assoc_only if true, only return assoc entry (default false)
|
||||
* @return array<mixed>|false row array or false on error
|
||||
@@ -2388,6 +2601,7 @@ class IO
|
||||
/**
|
||||
* creates an array of hashes of the query (all data)
|
||||
* Wrapper for dbReturnArrayParams
|
||||
*
|
||||
* @param string $query the query to be executed
|
||||
* @param bool $assoc_only if true, only name ref are returned (default true)
|
||||
* @return array<mixed>|false array of hashes (row -> fields), false on error
|
||||
@@ -2432,6 +2646,20 @@ class IO
|
||||
return $rows;
|
||||
}
|
||||
|
||||
// ***************************
|
||||
// CURSOR RETURN
|
||||
// ***************************
|
||||
|
||||
/**
|
||||
* Get current set cursor or false if not set or error
|
||||
*
|
||||
* @return \PgSql\Result|false
|
||||
*/
|
||||
public function dbGetCursor(): \PgSql\Result|false
|
||||
{
|
||||
return $this->cursor;
|
||||
}
|
||||
|
||||
// ***************************
|
||||
// CURSOR EXT CACHE RESET
|
||||
// ***************************
|
||||
@@ -2557,6 +2785,7 @@ class IO
|
||||
|
||||
/**
|
||||
* gets how often a query was called already
|
||||
*
|
||||
* @param string $query query string
|
||||
* @param array<mixed> $params If the query is params type we need params
|
||||
* data to create a unique call one, optional
|
||||
@@ -2581,6 +2810,7 @@ class IO
|
||||
* for INSERT INTO queries it is highly recommended
|
||||
* to set the pk_name to avoid an additional
|
||||
* read from the database for the PK NAME
|
||||
*
|
||||
* @param string $stm_name statement name
|
||||
* @param string $query queryt string to run
|
||||
* @param string $pk_name optional primary key
|
||||
@@ -2693,6 +2923,7 @@ class IO
|
||||
|
||||
/**
|
||||
* runs a prepare query
|
||||
*
|
||||
* @param string $stm_name statement name for the query to run
|
||||
* @param array<mixed> $data data to run for this query, empty array for none
|
||||
* @return \PgSql\Result|false false on error, or result on OK
|
||||
@@ -2791,6 +3022,7 @@ class IO
|
||||
* executes the query async so other methods can be run at the same time
|
||||
* Wrapper for dbExecParamsAsync
|
||||
* NEEDS : dbCheckAsync
|
||||
*
|
||||
* @param string $query query to run
|
||||
* @param string $pk_name optional primary key name, only used with
|
||||
* insert for returning call
|
||||
@@ -2890,6 +3122,7 @@ class IO
|
||||
/**
|
||||
* checks a previous async query and returns data if finished
|
||||
* NEEDS : dbExecAsync
|
||||
*
|
||||
* @return \PgSql\Result|bool cursor resource if the query is still running,
|
||||
* false if an error occured or cursor of that query
|
||||
*/
|
||||
@@ -2930,6 +3163,7 @@ class IO
|
||||
|
||||
/**
|
||||
* Returns the current async running query hash
|
||||
*
|
||||
* @return string Current async running query hash
|
||||
*/
|
||||
public function dbGetAsyncRunning(): string
|
||||
@@ -2948,6 +3182,7 @@ class IO
|
||||
|
||||
/**
|
||||
* writes into one table based on array of table columns
|
||||
*
|
||||
* @param array<mixed> $write_array list of elements to write
|
||||
* @param array<mixed> $not_write_array list of elements not to write
|
||||
* @param int $primary_key id key to decide if we write insert or update
|
||||
@@ -3163,6 +3398,54 @@ class IO
|
||||
return $this->db_debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param Convert $convert
|
||||
* @return void
|
||||
*/
|
||||
public function dbSetConvertFlag(Convert $convert): void
|
||||
{
|
||||
$this->convert_type |= $convert->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param Convert $convert
|
||||
* @return void
|
||||
*/
|
||||
public function dbUnsetConvertFlag(Convert $convert): void
|
||||
{
|
||||
$this->convert_type &= ~$convert->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset to origincal config file set
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dbResetConvertFlag(): void
|
||||
{
|
||||
foreach ($this->db_convert_type as $db_convert_type) {
|
||||
$this->__setConvertType($db_convert_type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @param Convert $convert
|
||||
* @return bool
|
||||
*/
|
||||
public function dbGetConvertFlag(Convert $convert): bool
|
||||
{
|
||||
if ($this->convert_type & $convert->value) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* set max query calls, set to -1 to disable loop
|
||||
* protection. this will generate a warning
|
||||
@@ -3314,12 +3597,11 @@ class IO
|
||||
* Alternative use dbSetEcnoding to trigger encoding change on the DB side
|
||||
* Set to empty string to turn off
|
||||
* @param string $encoding PHP Valid encoding to set
|
||||
* @return string Current set encoding
|
||||
* @return void
|
||||
*/
|
||||
public function dbSetToEncoding(string $encoding): string
|
||||
public function dbSetToEncoding(string $encoding): void
|
||||
{
|
||||
$this->to_encoding = $encoding;
|
||||
return $this->to_encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3555,6 +3837,45 @@ class IO
|
||||
return $this->field_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the field name to type connection list
|
||||
*
|
||||
* @return array<string,string>
|
||||
*/
|
||||
public function dbGetFieldNameTypes(): array
|
||||
{
|
||||
return $this->field_name_types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the field name for a position
|
||||
*
|
||||
* @param int $pos Position number in query
|
||||
* @return false|string Field name or false for not found
|
||||
*/
|
||||
public function dbGetFieldName(int $pos): false|string
|
||||
{
|
||||
return $this->field_names[$pos] ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a field type for a field name or pos,
|
||||
* will return false if field is not found in list
|
||||
*
|
||||
* @param string|int $name_pos Field name or pos to get the type for
|
||||
* @return false|string Either the field type or
|
||||
* false for not found in list
|
||||
*/
|
||||
public function dbGetFieldType(int|string $name_pos): false|string
|
||||
{
|
||||
if (is_numeric($name_pos)) {
|
||||
$field_type = $this->field_types[$name_pos] ?? false;
|
||||
} else {
|
||||
$field_type = $this->field_name_types[$name_pos] ?? false;
|
||||
}
|
||||
return $field_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for given key in statement
|
||||
* Will write error if statemen id does not exist
|
||||
|
||||
63
src/DB/Options/Convert.php
Normal file
63
src/DB/Options/Convert.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AUTOR: Clemens Schwaighofer
|
||||
* CREATED: 2023/6/9
|
||||
* DESCRIPTION:
|
||||
* DB Options for convert type
|
||||
*
|
||||
* off: no conversion (all string)
|
||||
* on: int/bool only
|
||||
* json: json/jsonb to array
|
||||
* numeric: any numeric or float to float
|
||||
* bytes: decode bytea to string
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace CoreLibs\DB\Options;
|
||||
|
||||
enum Convert: int
|
||||
{
|
||||
/** do not convert */
|
||||
case off = 0;
|
||||
/** convert only int/bool */
|
||||
case on = 1;
|
||||
/** also convert json to php array */
|
||||
case json = 2;
|
||||
/** also convert any float/real/numeric to php float */
|
||||
case numeric = 4;
|
||||
/** also decode bytea string to php string */
|
||||
case bytea = 8;
|
||||
|
||||
/**
|
||||
* get internal name from string value
|
||||
*
|
||||
* @param non-empty-string $name
|
||||
* @return self
|
||||
*/
|
||||
public static function fromName(string $name): self
|
||||
{
|
||||
return match ($name) {
|
||||
'Off', 'off', 'OFF', 'convert_off', 'CONVERT_OFF' => self::off,
|
||||
'On', 'on', 'ON', 'convert_on', 'CONVERT_ON' => self::on,
|
||||
'Json', 'json', 'JSON', 'convert_json', 'CONVERT_JSON' => self::json,
|
||||
'Numeric', 'numeric', 'NUMERIC', 'convert_numeric', 'CONVERT_NUMERIC' => self::numeric,
|
||||
'Bytea', 'bytea', 'BYTEA', 'convert_bytea', 'CONVERT_BYTEA' => self::bytea,
|
||||
default => self::off,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get internal name from int value
|
||||
*
|
||||
* @param int $value
|
||||
* @return self
|
||||
*/
|
||||
public static function fromValue(int $value): self
|
||||
{
|
||||
return self::from($value);
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
@@ -910,6 +910,42 @@ class Logging
|
||||
// MAIN CALLS
|
||||
// *********************************************************************
|
||||
|
||||
/**
|
||||
* Commong log interface
|
||||
*
|
||||
* extended with group_id, prefix that are ONLY used for debug level
|
||||
*
|
||||
* @param Level $level
|
||||
* @param string|\Stringable $message
|
||||
* @param mixed[] $context
|
||||
* @param string $group_id
|
||||
* @param string $prefix
|
||||
* @return bool
|
||||
*/
|
||||
public function log(
|
||||
Level $level,
|
||||
string|\Stringable $message,
|
||||
array $context = [],
|
||||
string $group_id = '',
|
||||
string $prefix = '',
|
||||
): bool {
|
||||
// if we are not debug, ignore group_id and prefix
|
||||
if ($level != Level::Debug) {
|
||||
$group_id = '';
|
||||
$prefix = '';
|
||||
}
|
||||
return $this->writeErrorMsg(
|
||||
$level,
|
||||
$this->prepareLog(
|
||||
$level,
|
||||
$prefix . $message,
|
||||
$context,
|
||||
$group_id
|
||||
),
|
||||
$group_id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* DEBUG: 100
|
||||
*
|
||||
@@ -917,18 +953,18 @@ class Logging
|
||||
*
|
||||
* @param string $group_id id for error message, groups messages together
|
||||
* @param string|Stringable $message the actual error message
|
||||
* @param mixed[] $context
|
||||
* @param string $prefix Attach some block before $string.
|
||||
* Will not be stripped even
|
||||
* when strip is true
|
||||
* if strip is false, recommended to add that to $string
|
||||
* @param mixed[] $context
|
||||
* @return bool True if logged, false if not logged
|
||||
*/
|
||||
public function debug(
|
||||
string $group_id,
|
||||
string|\Stringable $message,
|
||||
string $prefix = '',
|
||||
array $context = []
|
||||
array $context = [],
|
||||
string $prefix = ''
|
||||
): bool {
|
||||
return $this->writeErrorMsg(
|
||||
Level::Debug,
|
||||
|
||||
@@ -308,7 +308,8 @@ class Generate extends \CoreLibs\DB\Extended\ArrayIO
|
||||
/**
|
||||
* construct form generator
|
||||
*
|
||||
* @param array<mixed> $db_config db config array, mandatory
|
||||
* phpcs:ignore
|
||||
* @param array{db_name:string,db_user:string,db_pass:string,db_host:string,db_port:int,db_schema:string,db_encoding:string,db_type:string,db_ssl:string,db_convert_type?:string[]} $db_config db config array, mandatory
|
||||
* @param \CoreLibs\Logging\Logging $log Logging class
|
||||
* @param \CoreLibs\Language\L10n $l10n l10n language class
|
||||
* @param array<string,mixed> $login_acl Login ACL array,
|
||||
|
||||
@@ -36,6 +36,7 @@ class Image
|
||||
): string|false {
|
||||
// get image type flags
|
||||
$image_types = [
|
||||
0 => 'UNKOWN-IMAGE',
|
||||
1 => 'gif',
|
||||
2 => 'jpg',
|
||||
3 => 'png'
|
||||
@@ -69,7 +70,7 @@ class Image
|
||||
}
|
||||
// does this picture exist and is it a picture
|
||||
if (file_exists($filename) && is_file($filename)) {
|
||||
[$width, $height, $type] = getimagesize($filename) ?: [];
|
||||
[$width, $height, $type] = getimagesize($filename) ?: [0, 0, 0];
|
||||
$convert_prefix = '';
|
||||
$create_file = false;
|
||||
$delete_filename = '';
|
||||
@@ -98,7 +99,7 @@ class Image
|
||||
if (!is_file($filename)) {
|
||||
$filename .= '-0';
|
||||
}
|
||||
[$width, $height, $type] = getimagesize($filename) ?: [];
|
||||
[$width, $height, $type] = getimagesize($filename) ?: [0, 0, 0];
|
||||
}
|
||||
// if no size given, set size to original
|
||||
if (!$size_x || $size_x < 1) {
|
||||
@@ -117,7 +118,7 @@ class Image
|
||||
$status = exec($convert_string, $output, $return);
|
||||
// get the size of the converted data, if converted
|
||||
if (is_file($thumbnail)) {
|
||||
[$width, $height, $type] = getimagesize($thumbnail) ?: [];
|
||||
[$width, $height, $type] = getimagesize($thumbnail) ?: [0, 0, 0];
|
||||
}
|
||||
}
|
||||
if ($height > $size_y) {
|
||||
@@ -217,7 +218,7 @@ class Image
|
||||
return $thumbnail;
|
||||
}
|
||||
// $this->debug('IMAGE PREPARE', "FILENAME OK, THUMB WIDTH/HEIGHT OK");
|
||||
[$inc_width, $inc_height, $img_type] = getimagesize($filename) ?: [];
|
||||
[$inc_width, $inc_height, $img_type] = getimagesize($filename) ?: [0, 0, null];
|
||||
$thumbnail_write_path = null;
|
||||
$thumbnail_web_path = null;
|
||||
// path set first
|
||||
@@ -447,7 +448,7 @@ class Image
|
||||
if (!function_exists('exif_read_data') || !is_writeable($filename)) {
|
||||
return;
|
||||
}
|
||||
[$inc_width, $inc_height, $img_type] = getimagesize($filename) ?: [];
|
||||
[$inc_width, $inc_height, $img_type] = getimagesize($filename) ?: [0, 0, null];
|
||||
// add @ to avoid "file not supported error"
|
||||
$exif = @exif_read_data($filename);
|
||||
$orientation = null;
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace tests;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use CoreLibs\Logging\Logger\Level;
|
||||
use CoreLibs\DB\Options\Convert;
|
||||
|
||||
/**
|
||||
* Test class for DB\IO + DB\SQL\PgSQL
|
||||
@@ -4557,6 +4558,176 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
$db->dbClose();
|
||||
}
|
||||
|
||||
// testing auto convert
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @covers ::dbSetConvertFlag
|
||||
* @testdox Check convert type works
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testConvertType(): void
|
||||
{
|
||||
$db = new \CoreLibs\DB\IO(
|
||||
self::$db_config['valid'],
|
||||
self::$log
|
||||
);
|
||||
$bytea_data = $db->dbEscapeBytea(
|
||||
file_get_contents(__DIR__ . DIRECTORY_SEPARATOR . 'CoreLibsDBIOTest.php') ?: ''
|
||||
);
|
||||
$query_insert = <<<SQL
|
||||
INSERT INTO table_with_primary_key (
|
||||
uid,
|
||||
row_int, row_numeric, row_varchar, row_varchar_literal,
|
||||
row_json, row_jsonb, row_bytea, row_timestamp,
|
||||
row_date, row_interval, row_array_int, row_array_varchar
|
||||
) VALUES (
|
||||
$1,
|
||||
$2, $3, $4, $5,
|
||||
$6, $7, $8, $9,
|
||||
$10, $11, $12, $13
|
||||
)
|
||||
SQL;
|
||||
$db->dbExecParams(
|
||||
$query_insert,
|
||||
[
|
||||
'CONVERT_TYPE_TEST',
|
||||
1, 1.5, 'varchar', 'varchar literla',
|
||||
json_encode(['json', 'a', 1, true, 'sub' => ['b', 'c']]),
|
||||
json_encode(['jsonb', 'a', 1, true, 'sub' => ['b', 'c']]),
|
||||
$bytea_data, date('Y-m-d H:i:s'), date('Y-m-d'), date('H:m:s'),
|
||||
'{1,2,3}', '{"a","b","c"}'
|
||||
]
|
||||
);
|
||||
$type_layout = [
|
||||
'uid' => 'string',
|
||||
'row_int' => 'int',
|
||||
'row_numeric' => 'float',
|
||||
'row_varchar' => 'string',
|
||||
'row_varchar_literal' => 'string',
|
||||
'row_json' => 'json',
|
||||
'row_jsonb' => 'json',
|
||||
'row_bytea' => 'bytea',
|
||||
'row_timestamp' => 'string',
|
||||
'row_date' => 'string',
|
||||
'row_interval' => 'string',
|
||||
'row_array_int' => 'string',
|
||||
'row_array_varchar' => 'string'
|
||||
];
|
||||
$query_select = <<<SQL
|
||||
SELECT
|
||||
uid,
|
||||
row_int, row_numeric, row_varchar, row_varchar_literal,
|
||||
row_json, row_jsonb, row_bytea, row_timestamp,
|
||||
row_date, row_interval, row_array_int, row_array_varchar
|
||||
FROM
|
||||
table_with_primary_key
|
||||
WHERE
|
||||
uid = $1
|
||||
SQL;
|
||||
$res = $db->dbReturnRowParams($query_select, ['CONVERT_TYPE_TEST']);
|
||||
// all hast to be string
|
||||
foreach ($res as $key => $value) {
|
||||
$this->assertIsString($value, 'Aseert string for column: ' . $key);
|
||||
}
|
||||
// convert base only
|
||||
$db->dbSetConvertFlag(Convert::on);
|
||||
$res = $db->dbReturnRowParams($query_select, ['CONVERT_TYPE_TEST']);
|
||||
foreach ($res as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$name = $db->dbGetFieldName($key);
|
||||
} else {
|
||||
$name = $key;
|
||||
}
|
||||
switch ($type_layout[$name]) {
|
||||
case 'int':
|
||||
$this->assertIsInt($value, 'Aseert int for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
default:
|
||||
$this->assertIsString($value, 'Aseert string for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$db->dbSetConvertFlag(Convert::numeric);
|
||||
$res = $db->dbReturnRowParams($query_select, ['CONVERT_TYPE_TEST']);
|
||||
foreach ($res as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$name = $db->dbGetFieldName($key);
|
||||
} else {
|
||||
$name = $key;
|
||||
}
|
||||
switch ($type_layout[$name]) {
|
||||
case 'int':
|
||||
$this->assertIsInt($value, 'Aseert int for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
case 'float':
|
||||
$this->assertIsFloat($value, 'Aseert float for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
default:
|
||||
$this->assertIsString($value, 'Aseert string for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$db->dbSetConvertFlag(Convert::json);
|
||||
$res = $db->dbReturnRowParams($query_select, ['CONVERT_TYPE_TEST']);
|
||||
foreach ($res as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$name = $db->dbGetFieldName($key);
|
||||
} else {
|
||||
$name = $key;
|
||||
}
|
||||
switch ($type_layout[$name]) {
|
||||
case 'int':
|
||||
$this->assertIsInt($value, 'Aseert int for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
case 'float':
|
||||
$this->assertIsFloat($value, 'Aseert float for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
case 'json':
|
||||
case 'jsonb':
|
||||
$this->assertIsArray($value, 'Aseert array for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
default:
|
||||
$this->assertIsString($value, 'Aseert string for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
$db->dbSetConvertFlag(Convert::bytea);
|
||||
$res = $db->dbReturnRowParams($query_select, ['CONVERT_TYPE_TEST']);
|
||||
foreach ($res as $key => $value) {
|
||||
if (is_numeric($key)) {
|
||||
$name = $db->dbGetFieldName($key);
|
||||
} else {
|
||||
$name = $key;
|
||||
}
|
||||
switch ($type_layout[$name]) {
|
||||
case 'int':
|
||||
$this->assertIsInt($value, 'Aseert int for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
case 'float':
|
||||
$this->assertIsFloat($value, 'Aseert float for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
case 'json':
|
||||
case 'jsonb':
|
||||
$this->assertIsArray($value, 'Aseert array for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
case 'bytea':
|
||||
// for hex types it must not start with \x
|
||||
$this->assertStringStartsNotWith(
|
||||
'\x',
|
||||
$value,
|
||||
'Aseert bytes not starts with \x for column: ' . $key . '/' . $name
|
||||
);
|
||||
break;
|
||||
default:
|
||||
$this->assertIsString($value, 'Aseert string for column: ' . $key . '/' . $name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// - internal read data (post exec)
|
||||
// dbGetNumRows, dbGetNumFields, dbGetFieldNames,
|
||||
// dbGetQuery, dbGetQueryHash, dbGetDbh
|
||||
@@ -4588,7 +4759,7 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
. "('Foxtrott', 'Tango', 789, '1982-10-15') ",
|
||||
null,
|
||||
//
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
['row_varchar', 'row_varchar_literal', 'row_int', 'row_date'],
|
||||
['varchar', 'varchar', 'int4', 'date'],
|
||||
@@ -4705,9 +4876,16 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
$db->dbExecParams($query, $params);
|
||||
}
|
||||
|
||||
$this->assertInstanceOf(
|
||||
'PgSql\Result',
|
||||
$db->dbGetCursor(),
|
||||
'Failed assert dbGetCursor'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
$compare_query ?? $query,
|
||||
$db->dbGetQuery()
|
||||
$db->dbGetQuery(),
|
||||
'Failed assert dbGetQuery'
|
||||
);
|
||||
$this->assertEquals(
|
||||
// perhaps move that somewhere else?
|
||||
@@ -4720,7 +4898,8 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
($params === null ?
|
||||
$db->dbGetQueryHash($query) :
|
||||
$db->dbGetQueryHash($query, $params)
|
||||
)
|
||||
),
|
||||
'Failed assertdbGetQueryHash '
|
||||
);
|
||||
$this->assertEquals(
|
||||
$expected_rows,
|
||||
@@ -4742,6 +4921,35 @@ final class CoreLibsDBIOTest extends TestCase
|
||||
$db->dbGetFieldTypes(),
|
||||
'Failed assert dbGetFieldTypes'
|
||||
);
|
||||
// check FieldNameTypes matches
|
||||
$this->assertEquals(
|
||||
array_combine(
|
||||
$expected_col_names,
|
||||
$expected_col_types
|
||||
),
|
||||
$db->dbGetFieldNameTypes(),
|
||||
'Failed assert dbGetFieldNameTypes'
|
||||
);
|
||||
// check pos matches name
|
||||
// name matches type
|
||||
// pos matches type
|
||||
foreach ($expected_col_names as $pos => $name) {
|
||||
$this->assertEquals(
|
||||
$name,
|
||||
$db->dbGetFieldName($pos),
|
||||
'Failed assert dbGetFieldName: ' . $pos . ' => ' . $name
|
||||
);
|
||||
$this->assertEquals(
|
||||
$expected_col_types[$pos],
|
||||
$db->dbGetFieldType($name),
|
||||
'Failed assert dbGetFieldType: ' . $name . ' => ' . $expected_col_types[$pos]
|
||||
);
|
||||
$this->assertEquals(
|
||||
$expected_col_types[$pos],
|
||||
$db->dbGetFieldType($pos),
|
||||
'Failed assert dbGetFieldType: ' . $pos . ' => ' . $expected_col_types[$pos]
|
||||
);
|
||||
}
|
||||
$dbh = $db->dbGetDbh();
|
||||
$this->assertIsObject(
|
||||
$dbh
|
||||
|
||||
@@ -691,6 +691,11 @@ final class CoreLibsLoggingLoggingTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerLoggingLevelWrite(): array
|
||||
{
|
||||
return [
|
||||
@@ -796,6 +801,39 @@ final class CoreLibsLoggingLoggingTest extends TestCase
|
||||
);
|
||||
}
|
||||
|
||||
// check log level that writer writes in correct level
|
||||
// also that non debug ignores prefix/group
|
||||
|
||||
/**
|
||||
* Undocumented function
|
||||
*
|
||||
* @covers ::log
|
||||
* @testdox log() general call test
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testLoggingLog(): void
|
||||
{
|
||||
// init logger
|
||||
$log = new \CoreLibs\Logging\Logging([
|
||||
'log_file_id' => 'testLoggingLog',
|
||||
'log_folder' => self::LOG_FOLDER,
|
||||
'log_per_level' => true,
|
||||
]);
|
||||
$log_ok = $log->log(Level::Debug, 'DEBUG', group_id: 'GROUP_ID', prefix: 'PREFIX:');
|
||||
$this->assertTrue($log_ok, 'assert ::log (debug) OK');
|
||||
$this->assertEquals(
|
||||
$log->getLogFile(),
|
||||
$log->getLogFileId() . '_DEBUG.log'
|
||||
);
|
||||
$log_ok = $log->log(Level::Info, 'INFO', group_id: 'GROUP_ID', prefix: 'PREFIX:');
|
||||
$this->assertTrue($log_ok, 'assert ::log (info) OK');
|
||||
$this->assertEquals(
|
||||
$log->getLogFile(),
|
||||
$log->getLogFileId() . '_INFO.log'
|
||||
);
|
||||
}
|
||||
|
||||
// must test flow:
|
||||
// init normal
|
||||
// log -> check file name
|
||||
|
||||
Reference in New Issue
Block a user