Compare commits

...

4 Commits

Author SHA1 Message Date
Clemens Schwaighofer
11de4f9915 Logging update for class/method trace 2023-08-22 13:34:43 +09:00
Clemens Schwaighofer
dfb46d4f4a Release: v9.4.0 2023-08-22 13:33:08 +09:00
Clemens Schwaighofer
53c7dda9a0 JSON Array to convert fix, bool/false return fix 2023-08-02 16:34:57 +09:00
Clemens Schwaighofer
daf2706e7e Release: v9.3.6 2023-07-26 12:13:59 +09:00
13 changed files with 248 additions and 88 deletions

View File

@@ -16,7 +16,7 @@
],
"minimum-stability": "dev",
"require": {
"php": ">=8.1",
"php": ">=8.2",
"psr/log": "^3.0@dev"
},
"require-dev": {

View File

@@ -1 +1 @@
9.3.5
9.4.0

View File

@@ -556,7 +556,7 @@ class Backend
string $suffix = '',
int $min_steps = 1,
bool $name_pos_back = false
) {
): string {
// get the build layout
$html_time = \CoreLibs\Output\Form\Elements::printDateTime(
$year,

View File

@@ -169,10 +169,10 @@ class Email
* @param string $email email string
* @param bool $short default false, if true,
* returns only short type (pc instead of pc_html)
* @return string|bool email type, eg "pc", "docomo", etc,
* @return string|false email type, eg "pc", "docomo", etc,
* false for invalid short type
*/
public static function getEmailType(string $email, bool $short = false)
public static function getEmailType(string $email, bool $short = false): string|false
{
// trip if there is no email address
if (!$email) {
@@ -200,9 +200,9 @@ class Email
* gets the short email type from a long email type
*
* @param string $email_type email string
* @return string|bool short string or false for invalid
* @return string|false short string or false for invalid
*/
public static function getShortEmailType(string $email_type)
public static function getShortEmailType(string $email_type): string|false
{
// check if the short email type exists
if (isset(self::$mobile_email_type_short[$email_type])) {

View File

@@ -28,7 +28,7 @@ class Colors
* @param int $green green 0-255
* @param int $blue blue 0-255
* @param bool $hex_prefix default true, prefix with "#"
* @return string|bool rgb in hex values with leading # if set,
* @return string|false rgb in hex values with leading # if set,
* false for invalid color
*/
public static function rgb2hex(
@@ -36,7 +36,7 @@ class Colors
int $green,
int $blue,
bool $hex_prefix = true
): string|bool {
): string|false {
$hex_color = '';
if ($hex_prefix === true) {
$hex_color = '#';
@@ -58,14 +58,14 @@ class Colors
* @param string $hexStr RGB hexstring
* @param bool $return_as_string flag to return as string
* @param string $seperator string seperator: default: ","
* @return string|array<string,float|int>|bool false on error or array with RGB
* or a string with the seperator
* @return string|array<string,float|int>|false false on error or array with RGB
* or a string with the seperator
*/
public static function hex2rgb(
string $hexStr,
bool $return_as_string = false,
string $seperator = ','
): string|array|bool {
): string|array|false {
$hexStr = preg_replace("/[^0-9A-Fa-f]/", '', $hexStr); // Gets a proper hex string
if (!is_string($hexStr)) {
return false;
@@ -97,13 +97,13 @@ class Colors
* returns:
* array with hue (0-360), sat (0-100%), brightness/value (0-100%)
*
* @param int $red red 0-255
* @param int $green green 0-255
* @param int $blue blue 0-255
* @return array<int|float>|bool Hue, Sat, Brightness/Value
* false for input value error
* @param int $red red 0-255
* @param int $green green 0-255
* @param int $blue blue 0-255
* @return array<int|float>|false Hue, Sat, Brightness/Value
* false for input value error
*/
public static function rgb2hsb(int $red, int $green, int $blue): array|bool
public static function rgb2hsb(int $red, int $green, int $blue): array|false
{
// check that rgb is from 0 to 255
foreach (['red', 'green', 'blue'] as $c) {
@@ -144,13 +144,13 @@ class Colors
* converts HSB/V to RGB values RGB is full INT
* if HSB/V value is invalid, sets this value to 0
*
* @param float $H hue 0-360 (int)
* @param float $S saturation 0-100 (int)
* @param float $V brightness/value 0-100 (int)
* @return array<int>|bool 0 red/1 green/2 blue array as 0-255
* false for input value error
* @param float $H hue 0-360 (int)
* @param float $S saturation 0-100 (int)
* @param float $V brightness/value 0-100 (int)
* @return array<int>|false 0 red/1 green/2 blue array as 0-255
* false for input value error
*/
public static function hsb2rgb(float $H, float $S, float $V): array|bool
public static function hsb2rgb(float $H, float $S, float $V): array|false
{
// check that H is 0 to 359, 360 = 0
// and S and V are 0 to 1
@@ -230,13 +230,13 @@ class Colors
* return:
* array with hue (0-360), saturation (0-100%) and luminance (0-100%)
*
* @param int $red red 0-255
* @param int $green green 0-255
* @param int $blue blue 0-255
* @return array<float>|bool hue/sat/luminance
* false for input value error
* @param int $red red 0-255
* @param int $green green 0-255
* @param int $blue blue 0-255
* @return array<float>|false hue/sat/luminance
* false for input value error
*/
public static function rgb2hsl(int $red, int $green, int $blue): array|bool
public static function rgb2hsl(int $red, int $green, int $blue): array|false
{
// check that rgb is from 0 to 255
foreach (['red', 'green', 'blue'] as $c) {
@@ -284,12 +284,12 @@ class Colors
* converts an HSL to RGB
* if HSL value is invalid, set this value to 0
*
* @param float $hue hue: 0-360 (degrees)
* @param float $sat saturation: 0-100
* @param float $lum luminance: 0-100
* @return array<int,float|int>|bool red/blue/green 0-255 each
* @param float $hue hue: 0-360 (degrees)
* @param float $sat saturation: 0-100
* @param float $lum luminance: 0-100
* @return array<int,float|int>|false red/blue/green 0-255 each
*/
public static function hsl2rgb(float $hue, float $sat, float $lum): array|bool
public static function hsl2rgb(float $hue, float $sat, float $lum): array|false
{
if ($hue == 360) {
$hue = 0;

View File

@@ -48,8 +48,26 @@ class Json
return (array)$json;
}
/**
* convert array to json
* Will set empty json {} on false/error
* Error can be read with jsonGetLastError
* Deos not throw errors
*
* @param array<mixed> $data
* @param int $flags json_encode flags as is
* @return string JSON string or '{}' if false
*/
public static function jsonConvertArrayTo(array $data, int $flags = 0): string
{
$json_string = json_encode($data, $flags) ?: '{}';
self::$json_last_error = json_last_error();
return (string)$json_string;
}
/**
* returns human readable string for json errors thrown in jsonConvertToArray
* Source: https://www.php.net/manual/en/function.json-last-error.php
*
* @param bool $return_string [default=false] if set to true
* it will return the message string and not
@@ -80,6 +98,15 @@ class Json
case JSON_ERROR_UTF8:
$json_error_string = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
case JSON_ERROR_RECURSION:
$json_error_string = 'One or more recursive references in the value to be encoded';
break;
case JSON_ERROR_INF_OR_NAN:
$json_error_string = 'One or more NAN or INF values in the value to be encoded';
break;
case JSON_ERROR_UNSUPPORTED_TYPE:
$json_error_string = ' A value of a type that cannot be encoded was given';
break;
case JSON_ERROR_INVALID_PROPERTY_NAME:
$json_error_string = 'A key starting with \u0000 character was in the string';
break;

View File

@@ -805,7 +805,10 @@ class IO
$call_stack[] =
($call_trace['file'] ?? 'n/f') . ':'
. ($call_trace['line'] ?? '-') . ':'
. (!empty($call_trace['class']) ? $call_trace['class'] . '->' : '')
. (!empty($call_trace['class']) ?
$call_trace['class'] . ($call_trace['type'] ?? '') :
''
)
. $call_trace['function'];
}
$context = [
@@ -825,7 +828,7 @@ class IO
);
break;
default:
// used named arguments so we can easy change the order of debug
// used named arguments so we can easy change the order of debug
$this->log->debug(
group_id: $debug_id,
message: $error_string,
@@ -2779,7 +2782,7 @@ class IO
* @param string $query Query to find in cursor_ext
* @param array<mixed> $params If the query is params type we need params
* data to create a unique call one, optional
* @return int|false query position (row pos), false on error
* @return int|false numer of rows returned, false on error
*/
public function dbGetCursorNumRows(string $query, array $params = []): int|false
{
@@ -3736,7 +3739,7 @@ class IO
* Either a single element for a single insert or an array
* if multiple insert values where used.
*
* @return array<mixed>|string|int|null Current insert query primary key
* @return array<mixed>|string|int|null Current insert query primary key, null on not set
*/
public function dbGetInsertPK(): array|string|int|null
{

View File

@@ -405,7 +405,7 @@ class LoggingLegacy
// set per class, but don't use get_class as we will only get self
$rpl_string = !$this->log_per_class ? '' : '_'
// set sub class settings
. str_replace('\\', '-', Support::getCallerClass());
. str_replace('\\', '-', Support::getCallerTopLevelClass());
$fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename
// if request to write to one file
@@ -756,7 +756,7 @@ class LoggingLegacy
return $status;
}
// get the last class entry and wrie that
$class = Support::getCallerClass();
$class = Support::getCallerTopLevelClass();
// get timestamp
$timestamp = Support::printTime();
// same string put for print (no html data inside)
@@ -855,7 +855,7 @@ class LoggingLegacy
. 'border-bottom: 1px solid black; margin: 10px 0 10px 0; '
. 'background-color: white; color: black;">'
. '<div style="font-size: 12px;">{<span style="font-style: italic; color: #928100;">'
. Support::getCallerClass() . '</span>}</div>';
. Support::getCallerTopLevelClass() . '</span>}</div>';
$string_output = $string_prefix . $string_output
. '<div><span style="font-style: italic; color: #108db3;">Script Run Time:</span> '
. $script_end . '</div>'

View File

@@ -79,10 +79,10 @@ class Support
* default true: true, false: false
*
* @param bool $bool Variable to convert
* @param string $name [default: ''] Prefix name
* @param string $true [default: 'true'] True string
* @param string $false [default: 'false'] False string
* @param bool $no_html [default: false] if true do not print html
* @param string $name [=''] Prefix name
* @param string $true [='true'] True string
* @param string $false [='false'] False string
* @param bool $no_html [=false] if true do not print html
* @return string String with converted bool text for debug
*/
public static function printBool(
@@ -104,8 +104,8 @@ class Support
* Convert bool value to string value. Short name alias for printBool
*
* @param bool $bool Bool value to be transformed
* @param string $true [default: 'true'] Override default string 'true'
* @param string $false [default: 'false'] Override default string 'false'
* @param string $true [='true'] Override default string 'true'
* @param string $false [=false'] Override default string 'false'
* @return string $true or $false string for true/false bool
*/
public static function prBl(
@@ -159,7 +159,7 @@ class Support
* Recommended debug output
*
* @param mixed $data Anything
* @param bool $no_html [default=false] If true strip all html tags
* @param bool $no_html [=false] If true strip all html tags
* (for text print)
* @return string A text string
*/
@@ -203,7 +203,7 @@ class Support
* exports (dumps) var, in more printable design, but without detail info
*
* @param mixed $data Anything
* @param bool $no_html If true true do not add <pre> tags
* @param bool $no_html [=false] If true true do not add <pre> tags
* @return string A text string
*/
public static function exportVar(mixed $data, bool $no_html = false): string
@@ -217,7 +217,7 @@ class Support
* Return file name and line number where this was called
* One level up
*
* @param int $level trace level, default 1
* @param int $level [=1] trace level
* @return string|null null or file name:line number
*/
public static function getCallerFileLine(int $level = 1): ?string
@@ -238,14 +238,14 @@ class Support
* eg for debugging, this function does this
*
* call this method in the child method and you get the parent function that called
* @param int $level trace level, default 1
* @return ?string null or the function that called the function
* where this method is called
* @param int $level [=1] trace level
* @return string|null null or the function that called the function
* where this method is called
*/
public static function getCallerMethod(int $level = 1): ?string
{
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print \CoreLibs\Debug\Support::printAr($traces);
// print "getCallerMethod:<br>" . \CoreLibs\Debug\Support::printAr($traces);
// We should check from top down if unset?
// sets the start point here, and in level two (the sub call) we find this
if (isset($traces[$level])) {
@@ -254,6 +254,41 @@ class Support
return null;
}
/**
* get the class that first called it and skip the base class
* Companion method to getCallerMethod
*
* @param int $level [=1] trace level
* @return ?string null if class not found
*/
public static function getCallerClass(int $level = 1): ?string
{
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print "getCallerClass:<br>" . \CoreLibs\Debug\Support::printAr($traces);
if (isset($traces[$level])) {
return $traces[$level]['class'] ?? null;
}
return null;
}
/**
* Returns class and method together
*
* @param int $level [=1] travel level
* @return string|null null if trace level not found, else namespace class and method
*/
public static function getCallerClassMethod(int $level = 1): ?string
{
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print "getCallerClass:<br>" . \CoreLibs\Debug\Support::printAr($traces);
if (isset($traces[$level])) {
return ($traces[$level]['class'] ?? '-')
. ($traces[$level]['type'] ?? '')
. $traces[$level]['function'];
}
return null;
}
/**
* Returns array with all methods in the call stack in the order so that last
* called is last in order
@@ -283,25 +318,21 @@ class Support
* Is mostly used in debug log statements to get the class where the debug
* was called
* gets top level class
* loops over the debug backtrace until if finds the first class (from the end)
* loops over the debug backtrace until if finds the first class (from the end)
*
* @return string Class name with namespace
*/
public static function getCallerClass(): string
public static function getCallerTopLevelClass(): string
{
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// ?? [['class' => get_called_class()]];
// TODO make sure that this doesn't loop forver
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print "getCallerClass:<br>" . \CoreLibs\Debug\Support::printAr($traces);
$class = null;
while ($class === null && count($backtrace) > 0) {
// if current is
// [function] => debug
// [class] => CoreLibs\Debug\Logging
// then return
// (OUTSIDE) because it was not called from a class method
// or return file name
$get_class = array_pop($backtrace);
$class = $get_class['class'] ?? null;
// reverse and stop at first set class, this is the top level one
foreach (array_reverse($traces) as $trace) {
$class = $trace['class'] ?? null;
if (!empty($class)) {
break;
}
}
// on null or empty return empty string
return empty($class) ? '' : $class;

View File

@@ -381,7 +381,7 @@ class Logging
// auto set (should be deprecated in future)
$this->setLogFileId(
str_replace(':', '-', $this->host_name) . '_'
. str_replace('\\', '-', Support::getCallerClass())
. str_replace('\\', '-', Support::getCallerTopLevelClass())
);
}
if (empty($this->getLogFileId())) {
@@ -460,7 +460,7 @@ class Logging
// set per class, but don't use get_class as we will only get self
$rpl_string = !$this->getLogFlag(Flag::per_class) ? '' : '_'
// set sub class settings
. str_replace('\\', '-', Support::getCallerClass());
. str_replace('\\', '-', Support::getCallerTopLevelClass());
$fn = str_replace('{CLASS}', $rpl_string, $fn); // create output filename
// if request to write to one file
@@ -526,7 +526,10 @@ class Logging
/**
* Prepare the log message with all needed info blocks:
* [timestamp] [host name] [file path + file] [running uid] {class} <debug level/group id> - message
* [timestamp] [host name] [file path + file::row number] [running uid] {class::/->method}
* <debug level:debug group id> - message
* Note: group id is only for debug level
* if no method can be found or no class is found a - will be wirtten
*
* @param Level $level Log level we will write to
* @param string|Stringable $message The message to write
@@ -545,16 +548,32 @@ class Logging
if (!$this->checkLogLevel($level)) {
return '';
}
$file_line = '';
$caller_class_method = '-';
$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
// print "[" . $level->getName() . "] [$message] prepareLog:<br>" . Support::printAr($traces);
// file + line: call not this but one before (the one that calls this)
$file_line = Support::getCallerFileLine(2) ??
System::getPageName(System::FULL_PATH);
// get the last class entry and wrie that
$class = Support::getCallerClass();
// method/function: prepareLog->(debug|info|...)->[THIS]
$method = Support::getCallerMethod(3);
if ($method !== null) {
$class .= '::' . $method;
// start from this level, if unset fall down until we are at null
$start_trace_level = 2;
for ($trace_level = $start_trace_level; $trace_level >= 0; $trace_level--) {
if (isset($traces[$trace_level])) {
$file_line = ($traces[$trace_level]['file'] ?? $traces[$trace_level]['function'])
. ':' . ($traces[$trace_level]['line'] ?? '-');
// as namespace\class->method
$caller_class_method =
// get the last call before we are in the Logging class
($traces[$trace_level]['class'] ?? '')
// connector, if unkown use ==
. ($traces[$trace_level]['type'] ?? '')
// method/function: prepareLog->(debug|info|...)->[THIS]
. $traces[$trace_level]['function'];
break;
}
}
if (empty($file_line)) {
$file_line = System::getPageName(System::FULL_PATH);
}
// print "CLASS: " . $class . "<br>";
// get timestamp
$timestamp = Support::printTime();
@@ -574,7 +593,7 @@ class Logging
. '[' . $this->host_name . '] '
. '[' . $file_line . '] '
. '[' . $this->running_uid . '] '
. '{' . $class . '} '
. '{' . $caller_class_method . '} '
. '<' . strtoupper($group_str) . '> '
. $message
. $context_str;

View File

@@ -16,7 +16,7 @@ final class CoreLibsConvertJsonTest extends TestCase
/**
* test list for json convert tests
*
* @return array
* @return array<mixed>
*/
public function jsonProvider(): array
{
@@ -54,10 +54,36 @@ final class CoreLibsConvertJsonTest extends TestCase
];
}
/**
* Undocumented function
*
* @return array<mixed>
*/
public function jsonArrayProvider(): array
{
return [
'valid json' => [
[
'm' => 2,
'f' => 'sub_2'
],
'{"m":2,"f":"sub_2"}',
],
'empty json array' => [
[],
'[]'
],
'empty json hash' => [
['' => ''],
'{"":""}'
]
];
}
/**
* json error list
*
* @return array JSON error list
* @return array<mixed> JSON error list
*/
public function jsonErrorProvider(): array
{
@@ -127,7 +153,7 @@ final class CoreLibsConvertJsonTest extends TestCase
*
* @param string|null $input
* @param bool $flag
* @param array $expected
* @param array<mixed> $expected
* @return void
*/
public function testJsonConvertToArray(?string $input, bool $flag, array $expected): void
@@ -146,7 +172,8 @@ final class CoreLibsConvertJsonTest extends TestCase
* @testdox jsonGetLastError $input will be $expected_i/$expected_s [$_dataName]
*
* @param string|null $input
* @param string $expected
* @param int $expected_i
* @param string $expected_s
* @return void
*/
public function testJsonGetLastError(?string $input, int $expected_i, string $expected_s): void
@@ -161,6 +188,25 @@ final class CoreLibsConvertJsonTest extends TestCase
\CoreLibs\Convert\Json::jsonGetLastError(true)
);
}
/**
* Undocumented function
*
* @covers ::jsonConvertArrayTo
* @dataProvider jsonArrayProvider
* @testdox jsonConvertArrayTo $input (Override: $flag) will be $expected [$_dataName]
*
* @param array<mixed> $input
* @param string $expected
* @return void
*/
public function testJsonConvertArrayto(array $input, string $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Convert\Json::jsonConvertArrayTo($input)
);
}
}
// __END__

View File

@@ -562,10 +562,10 @@ final class CoreLibsDebugSupportTest extends TestCase
}
/**
* Undocumented function
* test the lowest one (one above base)
*
* @cover ::getCallerClass
* @testWith ["PHPUnit\\TextUI\\Command"]
* @testWith ["tests\\CoreLibsDebugSupportTest"]
* @testdox getCallerClass check if it returns $expected [$_dataName]
*
* @return void
@@ -578,6 +578,40 @@ final class CoreLibsDebugSupportTest extends TestCase
);
}
/**
* test highest return (top level)
*
* @cover ::getCallerTopLevelClass
* @testWith ["PHPUnit\\TextUI\\Command"]
* @testdox getCallerTopLevelClass check if it returns $expected [$_dataName]
*
* @return void
*/
public function testGetCallerTopLevelClass(string $expected): void
{
$this->assertEquals(
$expected,
Support::getCallerTopLevelClass()
);
}
/**
* test highest return (top level)
*
* @cover ::getCallerClassMethod
* @testWith ["tests\\CoreLibsDebugSupportTest->testGetCallerClassMethod"]
* @testdox getCallerClassMethod check if it returns $expected [$_dataName]
*
* @return void
*/
public function testGetCallerClassMethod(string $expected): void
{
$this->assertEquals(
$expected,
Support::getCallerClassMethod()
);
}
/**
* Undocumented function
*

View File

@@ -22,7 +22,7 @@ final class CoreLibsLoggingLoggingTest extends TestCase
. "\[[\w\.]+(:\d+)?\]\s{1}" // host:port
. "\[[\w\-\.\/]+:\d+\]\s{1}" // folder/file
. "\[\w+\]\s{1}" // run id
. "{[\w\\\\]+(::\w+)?}\s{1}"; // class
. "{[\w\\\\]+((::|->)\w+)?}\s{1}"; // class
public static function tearDownAfterClass(): void
{