diff --git a/.phan/config.php b/.phan/config.php index fd887576..10ee1641 100644 --- a/.phan/config.php +++ b/.phan/config.php @@ -26,6 +26,8 @@ use Phan\Config; return [ + // turn color on (-C) + "color_issue_messages_if_supported" => true, // If true, missing properties will be created when // they are first seen. If false, we'll report an // error message. @@ -36,7 +38,7 @@ return [ "null_casts_as_any_type" => false, // Backwards Compatibility Checking - 'backward_compatibility_checks' => true, + 'backward_compatibility_checks' => false, // Run a quick version of checks that takes less // time @@ -46,6 +48,12 @@ return [ // (0 is low severity, 5 is normal severity, 10 is critical) "minimum_severity" => 0, + // enable for dead code check + // this will spill out errors for all methods never called + // use after all is OK to try to find unused code blocks + // ignore recommended: PhanUnreferencedPublicMethod + // "dead_code_detection" => true, + // default false for include path check "enable_include_path_checks" => true, "include_paths" => [ @@ -120,6 +128,13 @@ return [ 'suppress_issue_types' => [ // 'PhanUndeclaredMethod', 'PhanEmptyFile', + // ignore unreferences public methods, etc here (for dead code check) + 'PhanUnreferencedPublicMethod', + 'PhanUnreferencedClass', + 'PhanWriteOnlyPublicProperty', + 'PhanUnreferencedConstant', + 'PhanWriteOnlyPublicProperty', + 'PhanReadOnlyPublicProperty' ], // Override to hardcode existence and types of (non-builtin) globals in the global scope. diff --git a/4dev/tests/CoreLibsDebugLoggingTest.php b/4dev/tests/CoreLibsDebugLoggingTest.php index 39152527..f9f952cf 100644 --- a/4dev/tests/CoreLibsDebugLoggingTest.php +++ b/4dev/tests/CoreLibsDebugLoggingTest.php @@ -15,6 +15,19 @@ final class CoreLibsDebugLoggingTest extends TestCase { public $log; + /** + * test set for options BASIC + * + * 0: options + * - null for NOT set + * 1: expected + * 2: override + * override: + * - constant for COSNTANTS + * - global for _GLOBALS + * + * @return array + */ public function optionsProvider(): array { return [ @@ -68,12 +81,395 @@ final class CoreLibsDebugLoggingTest extends TestCase ]; } - // init tests - // - __construct call with options + /** + * adds log ID settings based on basic options + * + * @return array + */ + public function logIdOptionsProvider(): array + { + // 0: options + // 1: expected + // 2: override + return [ + 'no log id set' => [ + null, + [ + 'log_file_id' => '' + ], + [] + ], + // set log id manually afterwards + 'set log id manually' => [ + null, + [ + 'log_file_id' => '', + 'set_log_file_id' => 'abc123', + ], + [ + // set post launch + 'values' => [ + 'log_file_id' => 'abc123' + ] + ] + ], + // set log id from options + 'set log id via options' => [ + [ + 'file_id' => 'abc456', + ], + [ + 'log_file_id' => 'abc456' + ], + [] + ], + // set log id from GLOBALS [DEPRECATED] + 'set log id via globals' => [ + null, + [ + 'log_file_id' => 'def123' + ], + [ + 'globals' => [ + 'LOG_FILE_ID' => 'def123' + ] + ] + ], + // set log id from CONSTANT [DEPRECATED] + 'set log id via constant' => [ + null, + [ + 'log_file_id' => 'ghi123' + ], + [ + // reset global + 'globals' => [ + 'LOG_FILE_ID' => null + ], + 'constant' => [ + 'LOG_FILE_ID' => 'ghi123' + ] + ] + ], + // invalid, keep previous set + 'invalid log id' => [ + [ + 'file_id' => 'jkl456' + ], + [ + 'log_file_id' => 'jkl456', + 'set_log_file_id' => 'jkl456', + ], + [ + 'values' => [ + 'log_file_id' => './#' + ] + ] + ] + ]; + } /** * Undocumented function * + * @return array + */ + public function logLevelAllProvider(): array + { + return [ + 'debug all true' => [ + 'debug', + true, + true, + true, + ], + 'echo all true' => [ + 'echo', + true, + true, + true, + ], + 'print all true' => [ + 'print', + true, + true, + true, + ], + 'set invalid level' => [ + 'invalud', + true, + false, + false, + ], + ]; + } + + /** + * Undocumented function + * + * @return array + */ + public function logLevelProvider(): array + { + return [ + 'set debug on for level A,B,C and check full set' => [ + 'debug', + 'on', + ['A', 'B', 'C'], + true, + null, + [ + 'A' => true, + 'B' => true, + 'C' => true, + ] + ], + 'set debug off for level A,B,C and check A' => [ + 'debug', + 'off', + ['A', 'B', 'C'], + true, + 'A', + true, + ], + // set one to false + 'set debug off for level A, B to false and check all' => [ + 'debug', + 'off', + ['A', 'B' => false], + true, + null, + [ + 'A' => true, + 'B' => false, + ], + ], + // set invalid type + 'set invalid level' => [ + 'invalid', + '', + [], + false, + null, + false + ], + // set invalid flag + 'set invalid on flag' => [ + 'print', + 'invalid', + [], + false, + null, + false + ], + // missing debug array set + 'missing debug level array' => [ + 'print', + 'off', + [], + false, + null, + [] + ], + // set but check no existing + 'set level but check no exisitng' => [ + 'print', + 'on', + ['A'], + true, + 'C', + false + ] + ]; + } + + /** + * Undocumented function + * + * @return array + */ + public function logPerProvider(): array + { + return [ + 'level set true' => [ + 'level', + true, + true, + true, + ], + 'class set true' => [ + 'class', + true, + true, + true, + ], + 'page set true' => [ + 'page', + true, + true, + true, + ], + 'run set true' => [ + 'run', + true, + true, + true, + ], + 'set invalid type' => [ + 'invalid', + true, + false, + false, + ] + ]; + } + + /** + * Undocumented function + * + * @return array + */ + public function prArProvider(): array + { + return [ + 'simple array' => [ + [ + 'A' => 'foobar' + ], + "##HTMLPRE##Array\n(\n" + . " [A] => foobar\n" + . ")\n" + . "##/HTMLPRE##" + ], + 'empty array' => [ + [], + "##HTMLPRE##Array\n(\n" + . ")\n" + . "##/HTMLPRE##" + ], + 'nested array' => [ + [ + 'A' => [ + 'B' => 'bar' + ] + ], + "##HTMLPRE##Array\n(\n" + . " [A] => Array\n" + . " (\n" + . " [B] => bar\n" + . " )\n" + . "\n" + . ")\n" + . "##/HTMLPRE##" + ], + ]; + } + + /** + * Undocumented function + * + * 0: array $options + * 1: array $debug_msg + * 2: boolean $expected_debug + * 3: string $expected_file + * 4: string $expected_string_start + * 5: string $expected_string_contains + * + * @return array + */ + public function debugProvider(): array + { + // error message to pass in + $error_msg['A'] = [ + 'level' => 'A', + 'string' => 'error msg', + 'strip' => false, + 'prefix' => '', + ]; + // file content to check + $file_msg['A'] = "{PHPUnit\TextUI\Command} - error msg\n"; + // string messages to check + $string_msg['A'] = [ + 's' => '
' + . '
{PHPUnit\TextUI\Command}' + . '
[A]
[', + 'c' => 'PHPUnit\TextUI\Command} - error msg
', + ]; + // array provider + return [ + 'A debug: on, print: on, echo: on' => [ + [ + 'debug_all' => true, + 'print_all' => true, + 'echo_all' => true, + ], + $error_msg['A'], + true, + $file_msg['A'], + $string_msg['A']['s'], + $string_msg['A']['c'], + ], + 'B debug: on, print: off, echo: on' => [ + [ + 'debug_all' => true, + 'print_all' => false, + 'echo_all' => true, + ], + $error_msg['A'], + true, + '', + $string_msg['A']['s'], + $string_msg['A']['c'], + ], + 'C debug: on, print: on, echo: off' => [ + [ + 'debug_all' => true, + 'print_all' => true, + 'echo_all' => false, + ], + $error_msg['A'], + true, + $file_msg['A'], + '', + '', + ], + 'D debug: on, print: off, echo: off' => [ + [ + 'debug_all' => true, + 'print_all' => false, + 'echo_all' => false, + ], + $error_msg['A'], + false, + '', + '', + '' + ], + 'E debug: off, print: off, echo: off' => [ + [ + 'debug_all' => false, + 'print_all' => false, + 'echo_all' => false, + ], + $error_msg['A'], + false, + '', + '', + '' + ] + // TODO more tests with different error messages + ]; + } + + /** + * init logging class + * * @dataProvider optionsProvider * @testdox init test [$_dataName] * @@ -101,34 +497,340 @@ final class CoreLibsDebugLoggingTest extends TestCase ); $this->assertEquals( $expected['debug_all'], - $this->log->getSetting('debug_all') + $this->log->getSetting('debug_output_all') ); $this->assertEquals( $expected['print_all'], - $this->log->getSetting('print_all') + $this->log->getSetting('print_output_all') ); - print "LOG: " . $this->log->getSetting('log_folder') . "\n"; - print "DEBUG: " . $this->log->getSetting('debug_all') . "\n"; - print "PRINT: " . $this->log->getSetting('print_all') . "\n"; + // print "LOG: " . $this->log->getSetting('log_folder') . "\n"; + // print "DEBUG: " . $this->log->getSetting('debug_output_all') . "\n"; + // print "PRINT: " . $this->log->getSetting('print_output_all') . "\n"; } - // setting tests - // - basicSetLogId - // - getLogId - // - setLogLevelAll - // - getLogLevelAll - // - debugFor - // - setLogLevel - // - getLogLevel - // - setLogPer - // - getLogPer - // debug tets - // - pr - // - debug - // - mergeErrors - // - printErrorMsg - // - resetErrorMsg - // - getErrorMsg + /** + * test the setting and getting of LogId + * + * @covers ::setLogId + * @dataProvider logIdOptionsProvider + * @testdox log id set/get tests [$_dataName] + * + * @param array|null $options + * @param array $expected + * @param array $override + * @return void + */ + public function testLogId(?array $options, array $expected, array $override): void + { + // we need to set with file_id option, globals LOG_FILE_ID, constant LOG_FILE_ID + if (!empty($override['constant'])) { + foreach ($override['constant'] as $var => $value) { + define($var, $value); + } + } + if (!empty($override['globals'])) { + foreach ($override['globals'] as $var => $value) { + $GLOBALS[$var] = $value; + } + } + if ($options === null) { + $this->log = new \CoreLibs\Debug\Logging(); + } else { + $this->log = new \CoreLibs\Debug\Logging($options); + } + // check current + $this->assertEquals( + $this->log->getLogId(), + $expected['log_file_id'] + ); + // we need to override now too + if (!empty($override['values'])) { + // check if we have values, set them post and assert + $this->log->basicSetLogId($override['values']['log_file_id']); + $this->assertEquals( + $this->log->getLogId(), + $expected['set_log_file_id'] + ); + } + } + + /** + * check set/get for log level all flag + * + * @dataProvider logLevelAllProvider + * @testdox set/get all log level $type with flag $flag [$_dataName] + * + * @param string $type + * @param bool $flag + * @param bool $expected_set + * @param bool $expected_get + * @return void + */ + public function testSetGetLogLevelAll( + string $type, + bool $flag, + bool $expected_set, + bool $expected_get + ): void { + // neutral start with default + $this->log = new \CoreLibs\Debug\Logging(); + // set and check + $this->assertEquals( + $this->log->setLogLevelAll($type, $flag), + $expected_set + ); + // get and check + $this->assertEquals( + $this->log->getLogLevelAll($type), + $expected_get + ); + } + + /** + * checks setting for per log info level + * + * @covers ::setLogLevel + * @dataProvider logLevelProvider + * @testdox set/get log level $type to $flag check with $level [$_dataName] + * + * @param string $type + * @param string $flag + * @param array $debug_on + * @param bool $expected_set + * @param string|null $level + * @param bool|array $expected_get + * @return void + */ + public function testSetGetLogLevel( + string $type, + string $flag, + array $debug_on, + bool $expected_set, + ?string $level, + $expected_get + ): void { + // neutral start with default + $this->log = new \CoreLibs\Debug\Logging(); + // set + $this->assertEquals( + $this->log->setLogLevel($type, $flag, $debug_on), + $expected_set + ); + // get, if level is null compare to? + $this->assertEquals( + $this->log->getLogLevel($type, $flag, $level), + $expected_get + ); + } + + /** + * set and get per log + * for level/class/page/run flags + * + * @covers ::setLogPer + * @dataProvider logPerProvider + * @testdox set/get log per $type with $set [$_dataName] + * + * @param string $type + * @param boolean $set + * @param boolean $expected_set + * @param boolean $expected_get + * @return void + */ + public function testSetGetLogPer( + string $type, + bool $set, + bool $expected_set, + bool $expected_get + ): void { + // neutral start with default + $this->log = new \CoreLibs\Debug\Logging(); + // set and check + $this->assertEquals( + $this->log->setLogPer($type, $set), + $expected_set + ); + // get and check + $this->assertEquals( + $this->log->getLogPer($type), + $expected_get + ); + } + + /** + * set the print log file date part + * + * @covers ::setGetLogPrintFileDate + * @testWith [true, true, true] + * [false, false, false] + * @testdox set/get log file date to $input [$_dataName] + * + * @param boolean $input + * @param boolean $expected_set + * @param boolean $expected_get + * @return void + */ + public function testSetGetLogPrintFileDate(bool $input, bool $expected_set, bool $expected_get): void + { + // neutral start with default + $this->log = new \CoreLibs\Debug\Logging(); + // set and check + $this->assertEquals( + $this->log->setGetLogPrintFileDate($input), + $expected_set + ); + $this->assertEquals( + $this->log->setGetLogPrintFileDate(), + $expected_get + ); + } + + /** + * convert array to string with ## pre replace space holders + * + * @covers ::prAr + * @dataProvider prArProvider + * @testdox check prAr array to string conversion [$_dataName] + * + * @param array $input + * @param string $expected + * @return void + */ + public function testPrAr(array $input, string $expected): void + { + $this->log = new \CoreLibs\Debug\Logging(); + $this->assertEquals( + $this->log->prAr($input), + $expected + ); + } + + // from here are complex debug tests + + /** + * Test debug flow + * + * @covers ::debug + * @dataProvider debugProvider + * @testdox check debug flow: $expected_debug [$_dataName] + * + * @param array $options + * @param array $debug_msg + * @param boolean $expected_debug + * @param string $expected_file + * @param string $expected_string_start + * @param string $expected_string_contains + * @return void + */ + public function testDebug( + array $options, + array $debug_msg, + bool $expected_debug, + string $expected_file, + string $expected_string_start, + string $expected_string_contains, + ): void { + // must run with below matrix + // level | debug | print | echo | debug() | printErrorMsg() | file + // A 1/1/1 | on | on | on | true | 'string' | on + // B 1/0/1 | on | off | on | true | 'string' | off + // C 1/1/0 | on | on | off | true | '' | on + // D 1/0/0 | on | off | off | false | '' | off + // E 0/1/1 | off | on | on | false | '' | off + // F 0/0/1 | off | off | on | false | '' | off + // G 0/1/0 | off | on | off | false | '' | off + // H 0/0/0 | off | off | off | false | '' | off + + + // * debug off + // return false on debug(), + // return false on writeErrorMsg() + // empty string on printErrorMsg + // * print off + // return true on debug(), + // return false on writeErrorMsg() + // empty string on printErrorMsg + // * echo off + // return true on debug(), + // empty string on printErrorMsg + // fillxed error_msg array + + // overwrite any previous set from test + $options['file_id'] = 'TestDebug'; + // set log folder to temp + $options['log_folder'] = '/tmp/'; + // remove any files named /tmp/error_log_TestDebug*.log + array_map('unlink', glob($options['log_folder'] . 'error_msg_' . $options['file_id'] . '*.log')); + // init logger + $this->log = new \CoreLibs\Debug\Logging($options); + // * debug (A/B) + // NULL check for strip/prefix + $this->assertEquals( + $this->log->debug( + $debug_msg['level'], + $debug_msg['string'], + $debug_msg['strip'], + $debug_msg['prefix'], + ), + $expected_debug + ); + // * if print check data in log file + $log_file = $this->log->getLogFileName(); + if (!empty($options['debug_all']) && !empty($options['print_all'])) { + // file name matching + $this->assertStringStartsWith( + $options['log_folder'] . 'error_msg_' . $options['file_id'], + $log_file, + ); + // cotents check + if (!is_file($log_file)) { + $this->fail('error msg file not found: ' . $log_file); + } else { + $log_data = file_get_contents($log_file); + if ($log_data === null) { + $this->fail('error msg file not readable or not data: ' . $log_file); + } + // file content matching + $this->assertStringEndsWith( + $expected_file, + $log_data, + ); + } + } else { + // there should be no file there + $this->assertEquals( + $log_file, + '' + ); + } + // ** ECHO ON + $log_string = $this->log->printErrorMsg(); + // * print + if (!empty($options['debug_all']) && !empty($options['echo_all'])) { + // print $this->log->printErrorMsg() . "\n"; + // echo string must start with + $this->assertStringStartsWith( + $expected_string_start, + $log_string + ); + // echo string must containt + $this->assertStringContainsString( + $expected_string_contains, + $log_string + ); + // TODO: as printing directly is not really done anymore tests below are todo + // * get error msg (getErrorMsg) + // * merge error msg (mergeErrors) + // * print merged (printErrorMsg) + // * reset A (resetErrorMsg) + // * reset ALL (resetErrorMsg) + } else { + $this->assertEquals( + $log_string, + '' + ); + } + } } // __END__ diff --git a/www/admin/class_test.debug.php b/www/admin/class_test.debug.php index e477a516..9ecbd919 100644 --- a/www/admin/class_test.debug.php +++ b/www/admin/class_test.debug.php @@ -87,6 +87,8 @@ $new_log = new CoreLibs\Debug\Logging([ ]); $new_log->debug('OPTIONS TYPE', 'New Type error'); print "OPTIONS LOGGER:
" . $new_log->printErrorMsg(); +$new_log->setLogLevel('debug', 'on', ['A', 'B', 'C' => false]); +print "LOG LEVEL: " . DebugSupport::printAr($new_log->getLogLevel('debug', 'on')) . "
"; echo "CLASS DEBUG CALL
"; diff --git a/www/lib/CoreLibs/Basic.php b/www/lib/CoreLibs/Basic.php index b99dedc3..20fbe1b7 100644 --- a/www/lib/CoreLibs/Basic.php +++ b/www/lib/CoreLibs/Basic.php @@ -173,7 +173,7 @@ class Basic public function basicSetLogId(string $string): string { trigger_error('Method ' . __METHOD__ . ' is deprecated, use $basic->log->basicSetLogId() or use \CoreLibs\Debug\Logging() class', E_USER_DEPRECATED); - return $this->log->basicSetLogId($string); + return $this->log->setLogId($string); } // ****** DEBUG/ERROR FUNCTIONS ****** @@ -263,7 +263,7 @@ class Basic { trigger_error('Method ' . __METHOD__ . ' is deprecated, use $basic->log->debugFor() or use \CoreLibs\Debug\Logging() class', E_USER_DEPRECATED); /** @phan-suppress-next-line PhanTypeMismatchArgumentReal, PhanParamTooFew @phpstan-ignore-next-line */ - $this->log->debugFor(...[func_get_args()]); + $this->log->setLogLevel(...[func_get_args()]); } /** diff --git a/www/lib/CoreLibs/DB/Extended/ArrayIO.php b/www/lib/CoreLibs/DB/Extended/ArrayIO.php index a20a21e9..dfe6885e 100644 --- a/www/lib/CoreLibs/DB/Extended/ArrayIO.php +++ b/www/lib/CoreLibs/DB/Extended/ArrayIO.php @@ -361,9 +361,6 @@ class ArrayIO extends \CoreLibs\DB\IO $this->table_array[$column]['value'] = ''; } else { if ($this->table_array[$column]['tmp'] != 'none' && $this->table_array[$column]['tmp']) { - // Dateiname zusammenbasteln: org-name + _pkid liste + .ext - list($name, $ext) = explode('.', $this->table_array[$column]['dn']); - // mozilla, patch $fn_name = explode('/', $this->table_array[$column]['dn']); $this->table_array[$column]['dn'] = $fn_name[count($fn_name) - 1]; diff --git a/www/lib/CoreLibs/Debug/Logging.php b/www/lib/CoreLibs/Debug/Logging.php index b11c0c4d..e4be8498 100644 --- a/www/lib/CoreLibs/Debug/Logging.php +++ b/www/lib/CoreLibs/Debug/Logging.php @@ -173,16 +173,17 @@ class Logging // can be overridden with basicSetLogFileId later if (!empty($this->options['file_id'])) { - $this->basicSetLogId($this->options['file_id'] ?? ''); + $this->setLogId($this->options['file_id'] ?? ''); } elseif (!empty($GLOBALS['LOG_FILE_ID'])) { // legacy flow, should be removed and only set via options - $this->basicSetLogId($GLOBALS['LOG_FILE_ID']); + $this->setLogId($GLOBALS['LOG_FILE_ID']); } elseif (defined('LOG_FILE_ID')) { - $this->basicSetLogId(LOG_FILE_ID); + // legacy flow, should be removed and only set via options + $this->setLogId(LOG_FILE_ID); } // init the log levels - $this->setLogLevels(); + $this->initLogLevels(); } // *** PRIVATE *** @@ -192,80 +193,84 @@ class Logging * * @return void */ - private function setLogLevels(): void + private function initLogLevels(): void { // if given via parameters, only for all // globals overrule given settings, for one (array), eg $ECHO['db'] = 1; - if (isset($this->options['debug']) && is_array($this->options['debug'])) { - $this->debug_output = $this->options['debug']; - } elseif (isset($GLOBALS['DEBUG']) && is_array($GLOBALS['DEBUG'])) { - $this->debug_output = $GLOBALS['DEBUG']; - } - if (isset($this->options['echo']) && is_array($this->options['echo'])) { - $this->debug_output = $this->options['echo']; - } elseif (isset($GLOBALS['ECHO']) && is_array($GLOBALS['ECHO'])) { - $this->echo_output = $GLOBALS['ECHO']; - } - if (isset($this->options['print']) && is_array($this->options['print'])) { - $this->debug_output = $this->options['print']; - } elseif (isset($GLOBALS['PRINT']) && is_array($GLOBALS['PRINT'])) { - $this->print_output = $GLOBALS['PRINT']; - } - - // exclude these ones from output - if (isset($this->options['debug_not']) && is_array($this->options['debug_not'])) { - $this->debug_output = $this->options['debug_not']; - } elseif (isset($GLOBALS['DEBUG_NOT']) && is_array($GLOBALS['DEBUG_NOT'])) { - $this->debug_output_not = $GLOBALS['DEBUG_NOT']; - } - if (isset($this->options['echo_not']) && is_array($this->options['echo_not'])) { - $this->debug_output = $this->options['echo_not']; - } elseif (isset($GLOBALS['ECHO_NOT']) && is_array($GLOBALS['ECHO_NOT'])) { - $this->echo_output_not = $GLOBALS['ECHO_NOT']; - } - if (isset($this->options['print_not']) && is_array($this->options['print_not'])) { - $this->debug_output = $this->options['print_not']; - } elseif (isset($GLOBALS['PRINT_NOT']) && is_array($GLOBALS['PRINT_NOT'])) { - $this->print_output_not = $GLOBALS['PRINT_NOT']; + foreach (['debug', 'echo', 'print'] as $type) { + // include or exclude (off) from output + foreach (['on', 'off'] as $flag) { + $in_type = $type; + if ($flag == 'off') { + $in_type .= '_not'; + } + $up_type = strtoupper($in_type); + if ( + isset($this->options[$in_type]) && + is_array($this->options[$in_type]) + ) { + $this->setLogLevel($type, $flag, $this->options[$in_type]); + } elseif ( + isset($GLOBALS[$up_type]) && + is_array($GLOBALS[$up_type]) + ) { + $this->setLogLevel($type, $flag, $GLOBALS[$up_type]); + } + } } // all overrule - $this->debug_output_all = + $this->setLogLevelAll( + 'debug', $this->options['debug_all'] ?? - $GLOBALS['DEBUG_ALL'] ?? - false; - $this->echo_output_all = + $GLOBALS['DEBUG_ALL'] ?? + false + ); + $this->setLogLevelAll( + 'echo', $this->options['echo_all'] ?? - $GLOBALS['ECHO_ALL'] ?? - false; - $this->print_output_all = + $GLOBALS['ECHO_ALL'] ?? + false + ); + $this->setLogLevelAll( + 'print', $this->options['print_all'] ?? - $GLOBALS['PRINT_ALL'] ?? - false; + $GLOBALS['PRINT_ALL'] ?? + false + ); // GLOBAL rules for log writing - $this->log_print_file_date = + $this->setGetLogPrintFileDate( $this->options['print_file_date'] ?? - $GLOBALS['LOG_PRINT_FILE_DATE'] ?? - true; - $this->log_per_level = + $GLOBALS['LOG_PRINT_FILE_DATE'] ?? + true + ); + $this->setLogPer( + 'level', $this->options['per_level'] ?? - $GLOBALS['LOG_PER_LEVEL'] ?? - false; - $this->log_per_class = + $GLOBALS['LOG_PER_LEVEL'] ?? + false + ); + $this->setLogPer( + 'class', $this->options['per_class'] ?? - $GLOBALS['LOG_PER_CLASS'] ?? - false; - $this->log_per_page = + $GLOBALS['LOG_PER_CLASS'] ?? + false + ); + $this->setLogPer( + 'page', $this->options['per_page'] ?? - $GLOBALS['LOG_PER_PAGE'] ?? - false; - $this->log_per_run = + $GLOBALS['LOG_PER_PAGE'] ?? + false + ); + $this->setLogPer( + 'run', $this->options['per_run'] ?? - $GLOBALS['LOG_PER_RUN'] ?? - false; + $GLOBALS['LOG_PER_RUN'] ?? + false + ); // set log per date - if ($this->log_print_file_date) { + if ($this->setGetLogPrintFileDate()) { $this->log_file_date = date('Y-m-d'); } // set per run ID @@ -295,46 +300,14 @@ class Logging { $access = false; // check if we do debug, echo or print - switch ($target) { - case 'debug': - if ( - ( - (isset($this->debug_output[$level]) && $this->debug_output[$level]) || - $this->debug_output_all - ) && - (!isset($this->debug_output_not[$level]) || - (isset($this->debug_output_not[$level]) && !$this->debug_output_not[$level]) - ) - ) { - $access = true; - } - break; - case 'echo': - if ( - ( - (isset($this->echo_output[$level]) && $this->echo_output[$level]) || - $this->echo_output_all - ) && - (!isset($this->echo_output_not[$level]) || - (isset($this->echo_output_not[$level]) && !$this->echo_output_not[$level]) - ) - ) { - $access = true; - } - break; - case 'print': - if ( - ( - (isset($this->print_output[$level]) && $this->print_output[$level]) || - $this->print_output_all - ) && - (!isset($this->print_output_not[$level]) || - (isset($this->print_output_not[$level]) && !$this->print_output_not[$level]) - ) - ) { - $access = true; - } - break; + if ( + ( + $this->getLogLevel($target, 'on', $level) || + $this->getLogLevelAll($target) + ) && + !$this->getLogLevel($target, 'off', $level) + ) { + $access = true; } return $access; } @@ -355,8 +328,6 @@ class Logging return false; } - // init output variable - $output = $error_string; // output formated error string to output file // init base file path $fn = $this->log_folder . $this->log_print_file . '.' . $this->log_file_name_ext; // log ID prefix settings, if not valid, replace with empty @@ -369,8 +340,10 @@ class Logging if ($this->log_per_run) { $rpl_string = '_' . $this->log_file_unique_id; // add 8 char unique string - } elseif ($this->log_print_file_date) { + } elseif ($this->setGetLogPrintFileDate()) { $rpl_string = '_' . $this->log_file_date; // add date to file + } else { + $rpl_string = ''; } $fn = str_replace('##DATE##', $rpl_string, $fn); // create output filename @@ -397,12 +370,13 @@ class Logging $this->log_file_name = $fn; $fp = fopen($this->log_file_name, 'a'); if ($fp !== false) { - fwrite($fp, $output); + fwrite($fp, $error_string); fclose($fp); + return true; } else { echo ""; + return false; } - return true; } // *** PUBLIC *** @@ -424,8 +398,21 @@ class Logging * if non valid string is given it returns the previous set one only * @param string $string log file id string value * @return string returns the set log file id string + * @deprecated Use $log->setLogId() */ public function basicSetLogId(string $string): string + { + return $this->setLogId($string); + } + + /** + * sets the internal log file prefix id + * string must be a alphanumeric string + * if non valid string is given it returns the previous set one only + * @param string $string log file id string value + * @return string returns the set log file id string + */ + public function setLogId(string $string): string { if (preg_match("/^[\w\-]+$/", $string)) { $this->log_file_id = $string; @@ -448,6 +435,7 @@ class Logging * @param string $flag on/off * array $array of levels to turn on/off debug * @return bool Return false if type or flag is invalid + * @deprecated Use setLogLevel */ public function debugFor(string $type, string $flag): bool { @@ -489,13 +477,15 @@ class Logging /** * passes list of level names, to turn on debug * eg $foo->debugFor('print', 'on', ['LOG', 'DEBUG', 'INFO']); - * TODO: currently we can only turn ON - * @param string $type debug, echo, print - * @param string $flag on/off - * array $array of levels to turn on/off debug - * @return bool Return false if type or falg invalid + * @param string $type debug, echo, print + * @param string $flag on/off + * @param array $debug_on Array of levels to turn on/off debug + * To turn off a level set 'Level' => false, + * If not set, switches to on + * @return bool Return false if type or flag invalid + * also false if debug array is empty */ - public function setLogLevel(string $type, string $flag): bool + public function setLogLevel(string $type, string $flag, array $debug_on): bool { // abort if not valid type if (!in_array($type, ['debug', 'echo', 'print'])) { @@ -505,14 +495,17 @@ class Logging if (!in_array($flag, ['on', 'off'])) { return false; } - $debug_on = func_get_args(); - array_shift($debug_on); // kick out type - array_shift($debug_on); // kick out flag (on/off) if (count($debug_on) >= 1) { - foreach ($debug_on as $level) { + foreach ($debug_on as $level => $set) { $switch = $type . '_output' . ($flag == 'off' ? '_not' : ''); - $this->{$switch}[$level] = true; + if (!is_bool($set)) { + $level = $set; + $set = true; + } + $this->{$switch}[$level] = $set; } + } else { + return false; } return true; } @@ -536,8 +529,8 @@ class Logging return false; } $switch = $type . '_output' . ($flag == 'off' ? '_not' : ''); - // bool - if ($level !== null) { + // log level direct check must be not null or not empty string + if (!empty($level)) { return $this->{$switch}[$level] ?? false; } // array @@ -576,6 +569,30 @@ class Logging return $this->{'log_per_' . $type}; } + /** + * Set or get the log file date extension flag + * if null or empty parameter gets current flag + * @param boolean|null $set Set the date suffix for log files + * If set to null return current set + * @return boolean Current set flag + */ + public function setGetLogPrintFileDate(?bool $set = null): bool + { + if ($set !== null) { + $this->log_print_file_date = $set; + } + return $this->log_print_file_date; + } + + /** + * Return current set log file name + * @return string Filename set set after the last time debug was called + */ + public function getLogFileName(): string + { + return $this->log_file_name; + } + /** * A replacement for the \CoreLibs\Debug\Support::printAr * But this does not wrap it in

@@ -602,10 +619,23 @@ class Logging
 	 *                        if strip is false, recommended to add that to $string
 	 * @return bool           True if logged, false if not logged
 	 */
-	public function debug(string $level, string $string, bool $strip = false, string $prefix = ''): bool
-	{
-		if (!$this->doDebugTrigger('debug', $level)) {
-			return false;
+	public function debug(
+		string $level,
+		string $string,
+		bool $strip = false,
+		string $prefix = ''
+	): bool {
+		$status = false;
+		// must be debug on and either echo or print on
+		if (
+			!$this->doDebugTrigger('debug', $level) ||
+			(
+				// if debug is on, either print or echo must be set to on
+				!$this->doDebugTrigger('print', $level) &&
+				!$this->doDebugTrigger('echo', $level)
+			)
+		) {
+			return $status;
 		}
 		// get the last class entry and wrie that
 		$class = Support::getCallerClass();
@@ -613,7 +643,7 @@ class Logging
 		$timestamp = Support::printTime();
 		// same string put for print (no html data inside)
 		// write to file if set
-		$this->writeErrorMsg(
+		$status = $this->writeErrorMsg(
 			$level,
 			'[' . $timestamp . '] '
 			. '[' . $this->host_name . '] '
@@ -662,66 +692,62 @@ class Logging
 					Html::htmlent($string)
 				)
 				. "
"; + $status = true; } - return true; + return $status; } /** - * merges the given error array with the one from this class - * only merges visible ones - * @param array $error_msg error array - * @return void has no return + * for ECHO ON only + * returns error data as string so it can be echoed out + * @param string $header_prefix prefix string for header + * @return string error msg for all levels */ - public function mergeErrors(array $error_msg = []): void - { - if (!is_array($error_msg)) { - $error_msg = []; - } - array_push($this->error_msg, ...$error_msg); - } - - /** - * prints out the error string - * @param string $string prefix string for header - * @return string error msg for all levels - */ - public function printErrorMsg(string $string = ''): string + public function printErrorMsg(string $header_prefix = ''): string { $string_output = ''; - if ($this->debug_output_all) { - if ($this->error_msg_prefix) { - $string = $this->error_msg_prefix; - } - $script_end = microtime(true) - $this->script_starttime; - foreach ($this->error_msg as $level => $temp_debug_output) { - if ($this->doDebugTrigger('debug', $level)) { - if ($this->doDebugTrigger('echo', $level)) { - $string_output .= '
' - . '[' . $level . '] ' - . ($string ? "**** " . Html::htmlent($string) . " ****
\n" : "") - . '
' - . join('', $temp_debug_output); - } // echo it out - } // do printout - } // for each level - // create the output wrapper around, so we have a nice formated output per class - if ($string_output) { - $string_prefix = '
' - . '
{' - . Support::getCallerClass() . '}
'; - $string_output = $string_prefix . $string_output - . '
Script Run Time: ' - . $script_end . '
' - . '
'; - } + // if not debug && echo on, do not return anything + if ( + !$this->getLogLevelAll('debug') || + !$this->getLogLevelAll('echo') + ) { + return $string_output; } + if ($this->error_msg_prefix) { + $header_prefix = $this->error_msg_prefix; + } + $script_end = microtime(true) - $this->script_starttime; + foreach ($this->error_msg as $level => $temp_debug_output) { + if ($this->doDebugTrigger('debug', $level)) { + if ($this->doDebugTrigger('echo', $level)) { + $string_output .= '
' + . '[' . $level . '] ' + . ($header_prefix ? "**** " . Html::htmlent($header_prefix) . " ****
\n" : '') + . '
' + . join('', $temp_debug_output); + } // echo it out + } // do printout + } // for each level + // create the output wrapper around + // so we have a nice formated output per class + if ($string_output) { + $string_prefix = '
' + . '
{' + . Support::getCallerClass() . '}
'; + $string_output = $string_prefix . $string_output + . '
Script Run Time: ' + . $script_end . '
' + . '
'; + } + // } return $string_output; } /** + * for ECHO ON only * unsests the error message array * can be used if writing is primary to file * if no level given resets all @@ -738,14 +764,26 @@ class Logging } /** + * for ECHO ON only * Get current error message array - * * @return array error messages collected */ public function getErrorMsg(): array { return $this->error_msg; } + + /** + * for ECHO ON only + * merges the given error array with the one from this class + * only merges visible ones + * @param array $error_msg error array + * @return void has no return + */ + public function mergeErrors(array $error_msg = []): void + { + array_push($this->error_msg, ...$error_msg); + } } // __END__